MST

星途 面试题库

面试题:C语言线程池动态调整中的资源管理

在C语言实现的Linux线程池模型中,当动态增加或减少线程池的线程数量时,如何妥善管理线程相关的资源,如线程栈空间、互斥锁、条件变量等,以避免资源泄漏和死锁问题?请详细阐述资源管理的策略和具体实现方式。
23.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

资源管理策略

  1. 线程栈空间
    • 动态分配:使用pthread_attr_setstacksize函数来设置线程栈的大小,在创建线程时根据实际需求动态分配栈空间。例如,如果预计线程执行的任务较为复杂,需要较大栈空间,可以适当增大栈的初始分配大小。
    • 释放:当线程结束时,线程栈空间会自动被操作系统回收,不需要手动干预。但在动态减少线程数量时,需要确保线程已经正常结束,避免线程还在执行过程中就被强制回收栈空间。
  2. 互斥锁
    • 初始化:在创建线程池时,使用pthread_mutex_init函数对互斥锁进行初始化。例如:
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  • 加锁与解锁:在访问共享资源(如任务队列)前,使用pthread_mutex_lock函数加锁,访问结束后使用pthread_mutex_unlock函数解锁。例如:
pthread_mutex_lock(&mutex);
// 访问共享资源
pthread_mutex_unlock(&mutex);
  • 动态增减线程时的处理:在动态增加或减少线程时,互斥锁的状态需要保持一致。增加线程时,新线程需要遵循相同的加锁解锁规则访问共享资源。减少线程时,在销毁线程前确保所有涉及共享资源的操作已经完成并且互斥锁处于解锁状态。
  • 销毁:在线程池销毁时,使用pthread_mutex_destroy函数销毁互斥锁,例如:
pthread_mutex_destroy(&mutex);
  1. 条件变量
    • 初始化:使用pthread_cond_init函数对条件变量进行初始化,例如:
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
  • 等待与唤醒:线程可以使用pthread_cond_wait函数等待条件变量满足,该函数会自动释放关联的互斥锁,当条件满足被唤醒后会重新获取互斥锁。例如:
pthread_mutex_lock(&mutex);
while (/* 条件不满足 */) {
    pthread_cond_wait(&cond, &mutex);
}
// 条件满足,继续执行
pthread_mutex_unlock(&mutex);

其他线程可以使用pthread_cond_signalpthread_cond_broadcast函数唤醒等待条件变量的线程。

  • 动态增减线程时的处理:增加线程时,新线程需要正确处理条件变量的等待和唤醒逻辑。减少线程时,需要考虑对等待在条件变量上的线程的影响,例如可以在减少线程前发送一个特殊信号通知等待线程有线程减少,以便它们进行相应处理。
  • 销毁:在线程池销毁时,使用pthread_cond_destroy函数销毁条件变量,例如:
pthread_cond_destroy(&cond);

具体实现方式示例

以下是一个简化的线程池实现,展示动态增减线程时资源管理的部分代码:

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>

#define MAX_THREADS 10
#define MAX_JOBS 100

// 任务结构体
typedef struct {
    void (*func)(void*);
    void *arg;
} job_t;

// 线程池结构体
typedef struct {
    job_t jobs[MAX_JOBS];
    int job_count;
    int job_front;
    int job_rear;
    pthread_mutex_t mutex;
    pthread_cond_t cond;
    pthread_t threads[MAX_THREADS];
    int thread_count;
    int running;
} thread_pool_t;

// 初始化线程池
void init_thread_pool(thread_pool_t *pool) {
    pool->job_count = 0;
    pool->job_front = 0;
    pool->job_rear = 0;
    pool->thread_count = 0;
    pool->running = 1;
    pthread_mutex_init(&pool->mutex, NULL);
    pthread_cond_init(&pool->cond, NULL);
}

// 添加任务到线程池
void add_job(thread_pool_t *pool, void (*func)(void*), void *arg) {
    pthread_mutex_lock(&pool->mutex);
    while (pool->job_count == MAX_JOBS) {
        pthread_cond_wait(&pool->cond, &pool->mutex);
    }
    pool->jobs[pool->job_rear].func = func;
    pool->jobs[pool->job_rear].arg = arg;
    pool->job_rear = (pool->job_rear + 1) % MAX_JOBS;
    pool->job_count++;
    pthread_cond_signal(&pool->cond);
    pthread_mutex_unlock(&pool->mutex);
}

// 线程执行函数
void* worker(void *arg) {
    thread_pool_t *pool = (thread_pool_t *)arg;
    while (1) {
        pthread_mutex_lock(&pool->mutex);
        while (pool->job_count == 0 && pool->running) {
            pthread_cond_wait(&pool->cond, &pool->mutex);
        }
        if (!pool->running && pool->job_count == 0) {
            pthread_mutex_unlock(&pool->mutex);
            pthread_exit(NULL);
        }
        job_t job = pool->jobs[pool->job_front];
        pool->job_front = (pool->job_front + 1) % MAX_JOBS;
        pool->job_count--;
        pthread_cond_signal(&pool->cond);
        pthread_mutex_unlock(&pool->mutex);

        job.func(job.arg);
    }
    return NULL;
}

// 动态增加线程
void add_thread(thread_pool_t *pool) {
    if (pool->thread_count < MAX_THREADS) {
        pthread_t tid;
        pthread_create(&tid, NULL, worker, pool);
        pool->threads[pool->thread_count++] = tid;
    }
}

// 动态减少线程
void remove_thread(thread_pool_t *pool) {
    if (pool->thread_count > 0) {
        pool->running = 0;
        pthread_cond_broadcast(&pool->cond);
        for (int i = 0; i < pool->thread_count; i++) {
            pthread_join(pool->threads[i], NULL);
        }
        pool->thread_count = 0;
        pool->running = 1;
    }
}

// 销毁线程池
void destroy_thread_pool(thread_pool_t *pool) {
    pool->running = 0;
    pthread_cond_broadcast(&pool->cond);
    for (int i = 0; i < pool->thread_count; i++) {
        pthread_join(pool->threads[i], NULL);
    }
    pthread_mutex_destroy(&pool->mutex);
    pthread_cond_destroy(&pool->cond);
}

// 示例任务函数
void example_job(void *arg) {
    printf("Job executed with arg: %d\n", *((int *)arg));
}

int main() {
    thread_pool_t pool;
    init_thread_pool(&pool);

    int arg1 = 1, arg2 = 2;
    add_job(&pool, example_job, &arg1);
    add_job(&pool, example_job, &arg2);

    add_thread(&pool);
    add_thread(&pool);

    sleep(2);
    remove_thread(&pool);

    destroy_thread_pool(&pool);
    return 0;
}

在上述代码中,通过合理使用互斥锁和条件变量来管理共享任务队列,并且在动态增加和减少线程时,遵循了正确的资源管理策略,避免了资源泄漏和死锁问题。