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);
}
每种方法的优点和缺点是什么?
What are the pros / cons of using pthread_cond_wait
or using a semaphore ?
I am waiting for a state change like this :
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);
Using a properly initialised semaphore, I think I could do it like this :
while(cam->status == WAIT_DISPLAY) {
sem_wait(&some_semaphore);
}
What are the pros and cons of each method ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
信号量非常适合生产者-消费者模型,尽管它还有其他用途。 您的程序逻辑负责确保针对等待次数发出正确数量的帖子。 如果您发布了一个信号量并且还没有人在等待它,那么当他们等待时,他们会立即继续。 如果您的问题可以用信号量的计数值来解释,那么使用信号量应该很容易解决。
条件变量在某些方面更宽容一些。 例如,您可以使用 cond_broadcast 唤醒所有服务员,而生产者不知道有多少服务员。 如果你 cond_signal 一个 condvar 而没有人在等待它,那么什么也不会发生。 如果您不知道是否会有听众感兴趣,这很好。 这也是为什么侦听器应该在等待之前始终检查互斥锁的状态 - 如果他们不这样做,那么他们可能会错过一个信号,并且直到下一个信号才会醒来(这可能永远不会)。
因此,条件变量适合通知感兴趣的各方状态已更改:您获取互斥体,更改状态,向 condvar 发出信号(或广播)并释放互斥体。 如果这描述了您的问题,那么您就处于 condvar 领域。 如果不同的听众对不同的状态感兴趣,您可以直接广播,他们会依次醒来,弄清楚他们是否找到了他们想要的状态,如果没有找到,则再次等待。
用互斥体和信号量尝试这种事情确实非常粗糙。 当您想要获取互斥锁、检查某些状态,然后等待信号量发生更改时,就会出现问题。 除非您可以自动释放互斥体并等待信号量(在 pthread 中不能),否则您最终会在持有互斥体的同时等待信号量。 这会阻止互斥体,这意味着其他人无法利用它来进行您关心的更改。 因此,您可能会想根据您的具体要求添加另一个互斥体。 也许还有另一个信号量。 结果通常是错误的代码和有害的竞争条件。
条件变量可以避免这个问题,因为调用 cond_wait 会自动释放互斥锁,以供其他人使用。 在 cond_wait 返回之前重新获得互斥体。
IIRC 可以仅使用信号量来实现一种 condvar,但是如果您要实现的与 condvar 一起使用的互斥体需要有 trylock,那么这是一个严重的令人头疼的问题,并且超时等待已经结束。 不建议。 因此,不要认为使用 condvar 可以做的任何事情都可以使用信号量完成。 另外,当然互斥体可以具有信号量所缺乏的良好行为,主要是避免优先级反转。
A semaphore is suited cleanly to a producer-consumer model, although it has other uses. Your program logic is responsible for ensuring that the right number of posts are made for the number of waits. If you post a semaphore and nobody is waiting on it yet, then when they do wait they continue immediately. If your problem is such that it can be explained in terms of the count value of a semaphore, then it should be easy to solve with a semaphore.
A condition variable is a bit more forgiving in some respects. You can for example use cond_broadcast to wake up all waiters, without the producer knowing how many there are. And if you cond_signal a condvar with nobody waiting on it then nothing happens. This is good if you don't know whether there's going to be a listener interested. It is also why the listener should always check the state with the mutex held before waiting - if they don't then they can miss a signal and not wake up until the next one (which could be never).
So a condition variable is suitable for notifying interested parties that state has changed: you acquire the mutex, change the state, signal (or broadcast) the condvar and release the mutex. If this describes your problem you're in condvar territory. If different listeners are interested in different states you can just broadcast and they'll each in turn wake up, figure out whether they've found the state they want, and if not wait again.
It's very gnarly indeed to attempt this sort of thing with a mutex and a semaphore. The problem comes when you want to take the mutex, check some state, then wait on the semaphore for changes. Unless you can atomically release the mutex and wait on the semaphore (which in pthreads you can't), you end up waiting on the semaphore while holding the mutex. This blocks the mutex, meaning that others can't take it to make the change you care about. So you will be tempted to add another mutex in a way which depends on your specific requirements. And maybe another semaphore. The result is generally incorrect code with harmful race conditions.
Condition variables escape this problem, because calling cond_wait automatically releases the mutex, freeing it for use by others. The mutex is regained before cond_wait returns.
IIRC it is possible to implement a kind of condvar using only semaphores, but if the mutex you're implementing to go with the condvar is required to have trylock, then it's a serious head-scratcher, and timed waits are out. Not recommended. So don't assume that anything you can do with a condvar can be done with semaphores. Plus of course mutexes can have nice behaviours that semaphores lack, principally priority-inversion avoidance.
第二个片段很活泼,不要这样做。
其他答案对相对优点进行了很好的讨论; 我只想补充一点,
pthread_cond_broadcast
是条件变量的明显优势。除此之外,我只是更习惯于为此条件变量,因为它们就是您在 Java 中使用的变量,甚至因为它们可以帮助您在检查共享标志时避免竞争。
事实上,在第二个片段中,您没有任何锁来保护 cam->status 的读取,因此它是通过数据竞争来访问的。 在这个特定的示例中,大多数平台都会让您摆脱这种情况,但 POSIX 和下一个 C/C++ 标准的内存模型具有未定义的语义。
事实上,如果另一个线程分配新的 cam 结构并覆盖 cam,则可能出现真正的竞争条件; 等待线程可能会看到“cam”指针的更新,但看不到 cam->status 的初始化。 事实上,在这种情况下以及一般情况下,第二个片段是在自找麻烦。
http://www.hpl.hp.com/personal/Hans_Boehm/c ++mm/
The 2nd snippet is racy, don't do that.
The other answers have a nice discussion of the relative merits; I'll just add that
pthread_cond_broadcast
is a clear advantage of condition variables.Beyond that, I'm just more used to condition variables for that, as they are what you use in Java, even because they help you to avoid races when checking the shared flags.
Indeed, in the 2nd snippet you don't have any lock protecting the read of cam->status, so it is accessed through a data race. Most platforms will let you get away with that in this particular example, but that has undefined semantics, by POSIX and by the memory model of the next C/C++ standards.
In fact, a real race condition is possible if another thread allocates a new cam structure and overwrites cam; the waiting thread might see the update to the 'cam' pointer without seeing the initialization of cam->status. Indeed, the 2nd snippet is asking for trouble, in this case and in general.
http://www.hpl.hp.com/personal/Hans_Boehm/c++mm/
条件允许你做一些信号量不能做的事情。
例如,假设您有一些需要互斥体的代码,称为
m
。 然而,它需要等待其他线程完成其任务,因此它等待一个名为s
的信号量。 现在,任何需要m
的线程都会被阻止运行,即使具有m
的线程正在等待s
。 这些类型的情况可以使用条件来解决。 当您等待条件时,当前持有的互斥锁将被释放,因此其他线程可以获取该互斥锁。 回到我们的示例,假设使用条件c
而不是s
。 我们的线程现在获取m
,然后有条件地等待c
。 这会释放m
以便其他线程可以继续进行。 当c
变得可用时,m
被重新获取,我们原来的线程可以愉快地继续前进。条件变量还允许您让所有等待条件变量的线程通过
pthread_cond_broadcast
继续进行。 此外,它还允许您执行定时等待,这样您就不会永远等待。当然,有时您不需要条件变量,因此根据您的要求,其中之一可能更好。
Conditionals let you do some things that semaphores won't.
For example, suppose you have some code which requires a mutex, called
m
. It however needs to wait until some other thread has finish their task, so it waits on a semaphore calleds
. Now any thread which needsm
is blocked from running, even though the thread which hasm
is waiting ons
. These kind of situations can be resolved using conditionals. When you wait on a conditional, the mutex currently held is released, so other threads can acquire the mutex. So back to our example, and suppose conditionalc
was used instead ofs
. Our thread now acquiresm
, and then conditional waits onc
. This releasesm
so other threads can proceed. Whenc
becomes available,m
is reacquired, and our original thread can continue merrily along its way.Conditional variables also allows you to let all threads waiting on a conditional variable to proceed via
pthread_cond_broadcast
. Additionally it also allows you to perform a timed wait so you don't end up waiting forever.Of course, sometimes you don't need conditional variables, so depending on your requirements, one or the other may be better.
这是完全错误的。 这很容易出现竞争状况。 当线程在 sem_Wait 上阻塞时,条件 cam->status == WAIT_DISPLAY 可能无法在系统中保持良好状态,因为其他线程可能已对其进行了修改。 因此,您的线程现在由于各种错误的原因而处于睡眠状态。
This is completely wrong. This is prone to race condition. By the time the thread blocks on sem_Wait, the condition cam->status == WAIT_DISPLAY may not hold good in the system as some other thread may have modified it. So, your thread is now sleeping for all wrong reasons.
在第二个片段中,您多次获得锁定,但从未释放它。
一般来说,你想要的状态可以完全用信号量来表达,那么你就可以使用它。 锁结构的尺寸较小,并且需要较少的原子操作来检查/设置/释放。
否则,如果状态很复杂,并且代码的不同部分等待同一变量的不同条件(例如,这里您想要 x<10;那里您想要 y>x),请使用 cond_wait。
In your second snippet, you're getting the lock multitude of times, never releasing it.
In general, the state you're waintin on can be completely expressed by a semaphore, then you can use just that. A lock structure is smaller in size, and it requires less atomic operations to check/set/release.
Otherwise, if the state is complex, and different parts of the code wait on different conditions of the same variable (eg, here you want x<10; there you want y>x), use cond_wait.