限制并发线程的数量(使用pthreads)

时间:2012-12-13 10:56:22

标签: c linux pthreads posix

我必须编写一个使用CURL在Web上发布信息的C应用程序。应用程序最多必须并行运行N(比如说10个)请求。我如何等待任何线程完成,而不是等待使用pthread_join()的特定线程。

我读到了pthread_cond_wait,但大多数示例都是控制线程(main)如何唤醒工作线程。我需要恰恰相反 - 工作线程必须能够在退出之前发出信号/唤醒父线程。

更新:实际上我需要一种让管理器线程休眠的方法,当工作线程完成它的工作时,它应该唤醒管理器线程以给它另一份工作。如果线程将结束并且将为作业创建新线程,则将使用线程池无关紧要。 Threre仍然需要一种向经理发出工作结束信号的方式。

我希望我不会得到这个建议

while(asleep){
  for(i = 0; i< threadCount; i++){
    pthread_mutex_lock(mutex);
    if(threads[i] == IDLE_STATE)
      startNewJob();
    pthread_mutex_unlock(mutex);
    usleep(100*1000);
  }
}

3 个答案:

答案 0 :(得分:4)

而不是创建/销毁点播线程,它&#39;会更容易在启动时创建的10个工作线程池,让你的主程序饲料工作给他们。

启动时,您将创建一个包含10名工作人员的阵列。这些可能看起来像

typedef struct worker
{
    pthread_t       thread;
    pthread_cond_t  cond;
    pthread_mutex_t mutex;
    struct job*     job;
    int             quit;
} worker;

管理员会通过设置job成员然后向工作人员发出信号,依次将作业委派给每个线程。

每个工作人员都会循环,直到quit为非零,等待其状态发出信号。在每个信号发出之后,它会在报告结果之前读取/处理其job,然后再次等待其状态。

编辑:您并不热衷于线程池。你可以尝试给每个线程一个唯一的id;在管理器中的每个线程的id和其他属性之间存储一些映射。当每个线程完成时,让它将其id添加到管理器拥有的列表中,然后在管理器中发出一个条件。每次管理器唤醒时,它都可以从列表中拉出头部,查找相应的线程,读回其作业结果然后加入线程。请注意,此处的管理器列表将由多个线程访问,因此读/写需要由互斥锁保护。

编辑2:您想了解更多有关条件的信息,并且找不到您认为有用的示例。我不确定这会更好,但这里some code I've writtenOsSemaphore*函数将条件包装到一个简单的Wait / Signal API中。

答案 1 :(得分:1)

您需要一个条件变量,与您一直在查看的相同功能,但只是转身。你正在等待的条件是“工人线程完成了一些工作”。

主线程确实:

  • lock mutex
  • 虽然没有线程完成:pthread_cond_wait
  • 解锁互斥锁
  • 安排工作

每个工作线程在完成工作时都会:

  • lock mutex
  • 标记已完成
  • 调用pthread_cond_signal
  • 解锁互斥锁
  • 退出或等待工作

答案 2 :(得分:1)

条件变量就是你所追求的。它们可以很容易地用来从工作线程发出管理器线程的信号,反之亦然。

最后你的稻草人示例实际上与你使用条件变量所做的非常相似:

pthread_mutex_lock(&mutex);
while (!finished) {
  for(i = 0; i < threadCount; i++) {
    if(threads[i] == IDLE_STATE)
      startNewJob(i);
  }

  /* Not finished, and no idle threads, so wait */
  if (!finished)
    pthread_cond_wait(&cond, &mutex);
}
pthread_mutex_unlock(&mutex);

线程完成后,它只会执行:

pthread_mutex_lock(&mutex);
threads[self] = IDLE_STATE;
pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);