我正在实现一个包含任务队列的线程。第一个任务添加到队列后,线程就会开始运行它。
我应该使用pthread条件变量来唤醒线程还是有更合适的机制?
如果我在pthread_cond_signal()
没有阻止其他线程时调用pthread_cond_wait()
而是做某事,会发生什么?信号会丢失吗?
答案 0 :(得分: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(¬_empty)
pthread_mutex_unlock(&queue_lock);
}
pop()
{
pthread_mutex_lock(&queue_lock);
if(queue.empty())
pthread_cond_wait(&queue_lock,¬_empty);
job=quque.pop();
pthread_mutex_unlock(&queue_lock);
}
答案 1 :(得分:11)
如果cond上当前没有线程被阻止,pthread_cond_broadcast()和pthread_cond_signal()函数将无效。
我建议你使用Semaphores。基本上,每次在队列中插入任务时,都会“提升”信号量。工作线程通过“向下”来阻塞信号量。由于每个任务都会“up”一次,所以只要队列中有任务,工作线程就会继续运行。当队列为空时,信号量为0,工作线程阻塞,直到新任务到达。当工作人员忙碌时,当超过1个任务到达时,信号量也很容易处理。请注意,您仍然必须锁定对队列的访问以保持插入/删除原子。
答案 2 :(得分:1)
信号将丢失,但您希望在这种情况下信号丢失。如果没有线程被唤醒,则该信号没有用处。 (如果没有人在等待什么,发生时不需要通知任何人,对吗?)
对于条件变量,丢失的信号不会导致线程“在火中睡觉”。除非您实际编写一个线程以便在已经发生火灾时进入休眠状态,否则无需“保存信号”。当火灾开始时,您的广播将唤醒任何睡眠线程。当你已经发生火灾时,你必须非常愚蠢地编写一个线程来进入睡眠状态。
答案 3 :(得分:0)
如前所述,信号量应该是最佳选择。如果你需要一个固定大小的队列,只需使用2个信号量(如经典的生产者 - 消费者)。
在artyom代码中,最好用pop()函数中的“while”替换“if”来处理虚假唤醒。
答案 4 :(得分:0)
没有效果。
如果检查pthread_condt_signal是如何实现的,condt会使用几个计数器来检查是否有任何等待线程被唤醒。例如,glibc-nptl
/* Are there any waiters to be woken? */
if (cond->__data.__total_seq > cond->__data.__wakeup_seq){
...
}