MST

星途 面试题库

面试题:C语言实现Linux线程池大小动态调整的关键步骤

在Linux环境下,使用C语言实现线程池模型时,若要实现线程池大小的动态调整,简述其关键的实现步骤,包括但不限于数据结构的设计与函数逻辑。
47.2万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试
  1. 数据结构设计
    • 线程池结构体
      typedef struct ThreadPool {
          pthread_t *threads; // 线程数组
          int thread_count; // 当前线程池中的线程数量
          int max_thread_count; // 线程池最大线程数量
          int min_thread_count; // 线程池最小线程数量
          int queue_size; // 任务队列大小
          int head; // 任务队列头
          int tail; // 任务队列尾
          int count; // 任务队列中任务数量
          void **task_queue; // 任务队列
          pthread_mutex_t lock; // 互斥锁,保护任务队列
          pthread_cond_t not_empty; // 条件变量,任务队列非空
          pthread_cond_t not_full; // 条件变量,任务队列非满
          int shutdown; // 线程池是否关闭标志
      } ThreadPool;
      
    • 任务结构体
      typedef struct Task {
          void (*func)(void *); // 任务执行函数
          void *arg; // 任务执行函数的参数
      } Task;
      
  2. 函数逻辑
    • 初始化线程池
      ThreadPool* createThreadPool(int min_count, int max_count, int queue_size) {
          ThreadPool *pool = (ThreadPool *)malloc(sizeof(ThreadPool));
          if (!pool) return NULL;
          pool->min_thread_count = min_count;
          pool->max_thread_count = max_count;
          pool->thread_count = min_count;
          pool->queue_size = queue_size;
          pool->head = 0;
          pool->tail = 0;
          pool->count = 0;
          pool->shutdown = 0;
          pool->threads = (pthread_t *)malloc(max_count * sizeof(pthread_t));
          pool->task_queue = (void **)malloc(queue_size * sizeof(void *));
          pthread_mutex_init(&pool->lock, NULL);
          pthread_cond_init(&pool->not_empty, NULL);
          pthread_cond_init(&pool->not_full, NULL);
          for (int i = 0; i < min_count; i++) {
              pthread_create(&pool->threads[i], NULL, worker, (void *)pool);
          }
          return pool;
      }
      
    • 工作线程函数
      void* worker(void *arg) {
          ThreadPool *pool = (ThreadPool *)arg;
          while (1) {
              pthread_mutex_lock(&pool->lock);
              while (pool->count == 0 &&!pool->shutdown) {
                  pthread_cond_wait(&pool->not_empty, &pool->lock);
              }
              if (pool->shutdown && pool->count == 0) {
                  pthread_mutex_unlock(&pool->lock);
                  pthread_exit(NULL);
              }
              Task *task = (Task *)pool->task_queue[pool->head];
              pool->head = (pool->head + 1) % pool->queue_size;
              pool->count--;
              pthread_cond_signal(&pool->not_full);
              pthread_mutex_unlock(&pool->lock);
              (*(task->func))(task->arg);
              free(task);
          }
          return NULL;
      }
      
    • 添加任务到线程池
      int addTask(ThreadPool *pool, void (*func)(void *), void *arg) {
          pthread_mutex_lock(&pool->lock);
          while (pool->count == pool->queue_size &&!pool->shutdown) {
              pthread_cond_wait(&pool->not_full, &pool->lock);
          }
          if (pool->shutdown) {
              pthread_mutex_unlock(&pool->lock);
              return -1;
          }
          Task *task = (Task *)malloc(sizeof(Task));
          task->func = func;
          task->arg = arg;
          pool->task_queue[pool->tail] = task;
          pool->tail = (pool->tail + 1) % pool->queue_size;
          pool->count++;
          pthread_cond_signal(&pool->not_empty);
          // 动态调整线程数,任务队列满且当前线程数小于最大线程数时,增加线程
          if (pool->count == pool->queue_size && pool->thread_count < pool->max_thread_count) {
              pthread_create(&pool->threads[pool->thread_count], NULL, worker, (void *)pool);
              pool->thread_count++;
          }
          pthread_mutex_unlock(&pool->lock);
          return 0;
      }
      
    • 销毁线程池
      void destroyThreadPool(ThreadPool *pool) {
          pthread_mutex_lock(&pool->lock);
          pool->shutdown = 1;
          pthread_cond_broadcast(&pool->not_empty);
          pthread_cond_broadcast(&pool->not_full);
          pthread_mutex_unlock(&pool->lock);
          for (int i = 0; i < pool->thread_count; i++) {
              pthread_join(pool->threads[i], NULL);
          }
          for (int i = 0; i < pool->count; i++) {
              Task *task = (Task *)pool->task_queue[i];
              free(task);
          }
          free(pool->threads);
          free(pool->task_queue);
          pthread_mutex_destroy(&pool->lock);
          pthread_cond_destroy(&pool->not_empty);
          pthread_cond_destroy(&pool->not_full);
          free(pool);
      }
      
  3. 动态调整线程池大小
    • 增加线程:在addTask函数中,当任务队列满(pool->count == pool->queue_size)且当前线程数小于最大线程数(pool->thread_count < pool->max_thread_count)时,通过pthread_create创建新的线程,加入到线程池中。
    • 减少线程:可以定期检查线程的忙碌状态(例如增加一个标志位记录线程是否在执行任务),当发现有过多的空闲线程(线程数大于最小线程数且有线程长时间空闲)时,可以让空闲线程退出。具体实现可在工作线程函数worker中添加逻辑,当满足空闲条件且线程数大于最小线程数时,线程自行退出。例如,在worker函数获取任务前,记录当前时间戳,若等待任务时间超过一定阈值且线程数大于最小线程数,线程可以调用pthread_exit退出。
    • 注意事项:在动态调整线程大小时,要注意对共享资源(如任务队列、线程数量等)的保护,使用互斥锁来确保数据一致性,避免出现竞态条件。同时,在条件变量的使用上要合理,确保线程能够正确地等待和唤醒。