关于C#:pthread_cond_wait与信号量

关于C#:pthread_cond_wait与信号量

pthread_cond_wait versus semaphore

使用pthread_cond_wait或使用信号量有什么优点/缺点?
我正在等待这样的状态更改:

1
2
3
4
5
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);

使用正确初始化的信号灯,我想我可以这样做:

1
2
3
while(cam->status == WAIT_DISPLAY) {
    sem_wait(&some_semaphore);
}

每种方法的优缺点是什么?


信号量完全适合生产者-消费者模型,尽管它还有其他用途。您的程序逻辑负责确保为等待的次数分配正确的帖子数。如果您发布了一个信号量,但还没有人在等待它,那么当他们等待时,它们会立即继续。如果您的问题足以用信号量的计数值来解释,那么使用信号量即可轻松解决。

条件变量在某些方面更具宽容性。例如,您可以使用cond_broadcast唤醒所有侍者,而生产者不知道有多少侍者。如果您cond_signal一个condvar,而没有人等待它,那么什么也不会发生。如果您不知道是否会有倾听者的兴趣,那就很好。这也是为什么侦听器应始终在等待之前检查是否保持了互斥锁的状态-如果不这样做,则它们可能会丢失信号,并且直到下一个信号之前都无法唤醒(这可能永远不会)。

因此,条件变量适用于通知相关方状态已更改:您获取互斥量,更改状态,向condvar发信号(或广播)并释放互斥量。如果这描述了您的问题,那么您就处于condvar领域。如果不同的侦听器对不同的状态感兴趣,您可以广播它们,然后每个人依次唤醒,找出他们是否已找到所需的状态,如果没有,请再次等待。

尝试使用互斥量和信号量进行此类操作确实很不顺手。当您要获取互斥锁,检查某些状态然后等待信号量进行更改时,就会出现问题。除非您可以原子地释放互斥锁并等待信号量(在pthread中是无法做到的),否则您最终会在握住互斥锁的同时等待信号量。这将阻止互斥锁,这意味着其他人无法接受它来进行您关心的更改。因此,您将倾向于根据自己的特定要求添加另一种互斥锁。也许还有另一个信号量。结果通常是带有有害竞争条件的错误代码。

条件变量可以避免此问题,因为调用cond_wait会自动释放互斥锁,将其释放给他人使用。在cond_wait返回之前重新获得互斥锁。

IIRC可以仅使用信号量来实现一种condvar,但是如果要实现与condvar一起使用的互斥锁必须具有trylock,则这是一个严重的难题,并且定时等待已到。不建议。因此,不要以为使用condvar可以做的任何事情都可以使用信号量来完成。加上互斥锁当然可以具有信号量所缺少的良好行为,主要是避免优先级反转。


根据条件,您可以执行某些信号量不会发生的事情。

例如,假设您有一些需要互斥量的代码,称为m。但是,它需要等到其他某个线程完成其任务后,才能等待名为s的信号量。现在,即使需要m的线程正在等待s,也将阻止所有需要m的线程运行。可以使用条件来解决这类情况。等待条件时,当前持有的互斥锁将被释放,以便其他线程可以获取该互斥锁。回到我们的示例,并假设使用条件c代替s。现在,我们的线程获取m,然后有条件地等待c。这会释放m,以便其他线程可以继续。当c可用时,将重新获取m,并且我们的原始线程可以沿其方式继续愉快地运行。

条件变量还允许您让所有等待条件变量的线程通过pthread_cond_broadcast进行处理。此外,它还允许您执行定时等待,这样您就不会永远等待。

当然,有时候您不需要条件变量,因此根据您的要求,一个或另一个可能更好。


第二个片段是活泼的,不要那样做。

其他答案对相对优点进行了很好的讨论;我只补充说pthread_cond_broadcast是条件变量的明显优势。

除此之外,我更习惯于为变量设置条件,因为它们就是您在Java中使用的变量,即使它们在检查共享标志时也可以帮助您避免竞争。

实际上,在第二个代码段中,您没有任何锁来保护cam-> status的读取,因此可以通过数据争用来访问它。在这个特定的示例中,大多数平台都将使您摆脱它的束缚,但是通过POSIX和下一个C / C标准的内存模型,它具有未定义的语义。

实际上,如果另一个线程分配了新的cam结构并覆盖cam,则可能出现真实的竞争条件;等待线程可能会看到对" cam"指针的更新,而没有看到cam-> status的初始化。确实,在这种情况下和一般情况下,第二个片段都在请求麻烦。

http://www.hpl.hp.com/personal/Hans_Boehm/c mm /


在第二个片段中,您将获得多次锁定,而从未释放过。

通常,您正在等待的状态可以完全由信号量表示,然后您可以使用它。锁结构的大小较小,并且需要较少的原子操作来检查/设置/释放。

否则,如果状态复杂,并且代码的不同部分在同一变量的不同条件下等待(例如,在此处您希望x <10;在此处您希望y> x),请使用cond_wait。


推荐阅读