pthread_cond_wait与信号量
使用pthread_cond_wait
或者使用信号量的优点/缺点是什么?
我正在等待这样的状态更改:
pthread_mutex_lock(&cam->video_lock); while(cam->status == WAIT_DISPLAY) { pthread_cond_wait(&cam->video_cond, &cam->video_lock); } pthread_mutex_unlock(&cam->video_lock);
我认为可以使用正确初始化的信号量来做到这一点:
while(cam->status == WAIT_DISPLAY) { sem_wait(&some_semaphore); }
每种方法的优缺点是什么?
解决方案
回答
在第二个片段中,我们将获得无数次锁定,而从不释放它。
通常,我们正在等待的状态可以完全由信号量表示,然后我们可以使用它。锁结构较小,并且需要较少的原子操作来检查/设置/释放。
否则,如果状态复杂,并且代码的不同部分在同一变量的不同条件下等待(例如,在此处我们希望x <10;在此处我们希望y> x),请使用cond_wait。
回答
条件语句使我们可以执行信号量不会执行的某些操作。
例如,假设我们有一些需要互斥量的代码,称为" m"。但是,它需要等到其他线程完成其任务后,才能等待名为" s"的信号量。现在,即使有m
的线程正在等待s
,所有需要m
的线程也被阻止运行。可以使用条件来解决此类情况。当我们等待条件时,当前持有的互斥锁将被释放,以便其他线程可以获取该互斥锁。回到我们的示例,并假设使用条件c代替了s。现在,我们的线程获取m
,然后有条件地等待c
。这样会释放m
,以便其他线程可以继续。当c
可用时,将重新获得m
,并且我们的原始线程可以继续愉快地前进。
条件变量还允许我们让所有等待条件变量的线程通过pthread_cond_broadcast
进行处理。此外,它还允许我们执行定时等待,这样我们就不会永远等待。
当然,有时我们不需要条件变量,因此根据要求,一个或者另一个可能更好。
回答
尽管信号量还有其他用途,但它完全适合生产者-消费者模型。程序逻辑负责确保为等待的次数分配正确的帖子数。如果我们发布了一个信号量,但是还没有人在等待它,那么当他们等待时,它们会立即继续。如果问题可以用信号量的计数值来解释,那么使用信号量应该很容易解决。
条件变量在某些方面更具宽容性。例如,我们可以使用cond_broadcast唤醒所有侍者,而生产者不知道有多少侍者。如果我们cond_signal一个condvar,而没有人等待它,那么什么也不会发生。如果我们不知道是否会有倾听者的兴趣,那就很好。这也是为什么侦听器在等待互斥量之前始终检查其状态的原因,否则它们可能会错过一个信号并且直到下一个信号之前都无法唤醒(这可能永远不会)。
因此,条件变量适合于通知相关方状态已更改:获取互斥量,更改状态,用信号通知(或者广播)condvar并释放互斥量。如果这描述了问题,那么我们就处于condvar领域。如果不同的侦听器对不同的状态感兴趣,则可以广播,然后每个人依次唤醒,找出他们是否已找到所需的状态,如果没有,请再次等待。
尝试使用互斥量和信号量进行此类操作确实很不明智。当我们要获取互斥锁,检查某些状态然后等待信号灯进行更改时,就会出现问题。除非我们可以原子地释放互斥锁并等待信号量(在pthread中是不可能的),否则我们最终会在拿着互斥锁的同时等待信号量。这将阻止互斥锁,这意味着其他人无法接受它来进行我们关心的更改。因此,我们将倾向于根据自己的特定要求添加另一种互斥锁。也许还有另一个信号量。结果通常是带有有害竞争条件的错误代码。
条件变量可以避免此问题,因为调用cond_wait会自动释放互斥锁,将其释放给他人使用。在cond_wait返回之前,将重新获得互斥锁。
IIRC可以仅使用信号量来实现一种condvar,但是如果我们要与condvar一起实现的互斥锁需要具有trylock,则这是一个严重的难题,并且定时等待已到。不建议。因此,不要以为使用condvar可以做的任何事情都可以使用信号量来完成。加上互斥体当然可以具有信号量所缺乏的良好行为,主要是避免优先级反转。
回答
第二个片段是活泼的,不要那样做。
其他答案对相对优点进行了很好的讨论。我只是补充说,pthread_cond_broadcast
是条件变量的明显优势。
除此之外,我只是更习惯于对变量进行条件化,因为它们是我们在Java中使用的变量,即使它们在检查共享标志时也可以避免竞争。
确实,在第二个代码段中,我们没有任何锁来保护cam-> status的读取,因此可以通过数据竞争来访问它。在这个特定的示例中,大多数平台都将使我们摆脱它的束缚,但是通过POSIX和下一个C / C ++标准的内存模型,它具有未定义的语义。
实际上,如果另一个线程分配了一个新的cam结构并覆盖cam,则可能出现真实的竞争情况。等待线程可能会看到对" cam"指针的更新,而没有看到cam-> status的初始化。确实,在这种情况下和一般情况下,第二个片段都在请求麻烦。
http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/