8

我正在实现一个带有任务队列的线程。一旦第一个任务被添加到队列中,线程就开始运行它。

我应该使用 pthread 条件变量来唤醒线程还是有更合适的机制?

如果我pthread_cond_signal()在另一个线程没有被阻塞pthread_cond_wait()而是在做某事时调用,会发生什么?信号会丢失吗?

4

5 回答 5

12

pthread_cond_signal 手册

如果当前没有线程阻塞在 cond 上,pthread_cond_broadcast() 和 pthread_cond_signal() 函数将无效。

我建议你使用信号量。基本上,每次将任务插入队列时,您都会“启动”信号量。工作线程通过“关闭”信号量来阻塞信号量。由于每个任务都会“向上”一次,因此只要队列中有任务,工作线程就会继续运行。当队列为空时,信号量为 0,工作线程阻塞,直到有新任务到达。信号量也很容易处理当工作人员忙时有超过 1 个任务到达的情况。请注意,您仍然必须锁定对队列的访问以保持插入/删除的原子性。

于 2009-02-08T10:22:57.853 回答
12

如果您的队列已经是线程安全的,那么信号量是好的。此外,一些信号量实现可能会受到最高计数器值的限制。即使您不太可能超过最大值。

执行此操作的最简单和正确的方法如下:

pthread_mutex_t queue_lock;
pthread_cond_t  not_empty;
queue_t queue;

push()
{
  pthread_mutex_lock(&queue_lock);
  queue.insert(new_job);
  pthread_cond_signal(&not_empty)
  pthread_mutex_unlock(&queue_lock);
}
pop()
{
  pthread_mutex_lock(&queue_lock);
  if(queue.empty()) 
     pthread_cond_wait(&queue_lock,&not_empty);
  job=quque.pop();
  pthread_mutex_unlock(&queue_lock);
}
于 2009-02-08T14:44:43.253 回答
1

信号将丢失,但您希望在这种情况下丢失信号。如果没有要唤醒的线程,则该信号毫无用处。(如果没有人在等待某事,那么当它发生时也不需要通知任何人,对吧?)

使用条件变量,丢失的信号不会导致线程“睡过火”。除非您在已经发生火灾时实际编写线程以进入睡眠状态,否则无需“保存信号”。当火灾开始时,您的广播将唤醒所有休眠线程。当已经发生火灾时,您必须非常愚蠢地编写一个线程以进入睡眠状态。

于 2011-09-02T11:03:11.267 回答
0

如前所述,信号量应该是最佳选择。如果您需要一个固定大小的队列,只需使用 2 个信号量(如在经典的生产者-消费者中)。

在 artyom 代码中,最好将 pop() 函数中的“if”替换为“while”,以处理虚假唤醒。

于 2013-01-08T08:33:44.427 回答
0

没有影响。

如果你检查 pthread_condt_signal 是如何实现的,condt 使用几个计数器来检查是否有任何等待线程唤醒。例如,glibc-nptl

 /* Are there any waiters to be woken?  */
 if (cond->__data.__total_seq > cond->__data.__wakeup_seq){
    ...
 }
于 2014-06-11T09:50:57.260 回答