C语言 pthread_cond_wait(&cond_t, &mutex); 解锁然后锁定互斥锁?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/14924469/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Does pthread_cond_wait(&cond_t, &mutex); unlock and then lock the mutex?
提问by MOHAMED
I m using pthread_cond_wait(&cond_t, &mutex);in my program and I m wondering why this function need as a second parameter a mutex variable.
我pthread_cond_wait(&cond_t, &mutex);在我的程序中使用,我想知道为什么这个函数需要一个互斥变量作为第二个参数。
Does the pthread_cond_wait()unlock the mutex at the beggining (beggining of the execution pthread_cond_wait()) and then locked when it finish (just before leaving pthread_cond_wait())?
是否pthread_cond_wait()在开始时(开始执行pthread_cond_wait())解锁互斥锁,然后在完成时(就在离开之前pthread_cond_wait())锁定?
采纳答案by LihO
When the first thread calls pthread_cond_wait(&cond_t, &mutex);it releases the mutex and it waits till condition cond_tis signaled as complete andmutexis available.
当第一个线程调用pthread_cond_wait(&cond_t, &mutex);它时,它会释放互斥锁并等待,直到条件cond_t被指示为完成并且mutex可用。
So when pthread_cond_signalis called in the other thread, it doesn't "wake up" the thread that waits yet. mutexmust be unlocked first, only then there is a chance that first thread will get a lock, which means that "upon successful return of pthread_cond_waitmutex shall have been locked and shall be owned by the calling thread."
所以当pthread_cond_signal在另一个线程中被调用时,它不会“唤醒”等待的线程。mutex必须先解锁,只有这样第一个线程才有机会获得锁,这意味着“成功返回pthread_cond_wait互斥锁后,应已锁定并由调用线程拥有”。
回答by WhozCraig
There are manytext on the subject of condition variables and their usage, so I'll not bore you with a ton of ugly details. The reason they exist at all is to allow you to notify change in a predicatestate. The following are criticalin understanding proper use of condition variables and their mutex association:
关于条件变量及其用法的主题有很多文本,因此我不会用大量丑陋的细节让您感到厌烦。它们存在的根本原因是允许您通知谓词状态的更改。以下是关键的理解正确使用条件变量及其互斥的关联:
pthread_cond_wait()simultaneously unlocksthe mutex andbegins waiting for the condition variable to be signalled. thus you must alwayshave ownership of the mutex before invoking it.pthread_cond_wait()returns with the mutex locked, thus you must unlock the mutex to allow its use somewhere else when finished with it. Whether the return happened because the condition variable was signalled or not isn't relevant. You still need to check your predicate regardless to account for potential spurious wakeups.The purpose of the mutex is notto protect the condition variable; it is to protect the predicateon which the condition variable is being used as a signaling mechanism. This is hands-down the most often misunderstood idiom of pthread condition variables and their mutexes. The condition variable doesn't need mutual exclusion protection; the predicate data does. Think of the predicate as an outside-state which is being monitored by the users of the condition-variable/mutex pair.
pthread_cond_wait()同时解锁互斥锁并开始等待条件变量发出信号。因此,在调用它之前,您必须始终拥有互斥锁的所有权。pthread_cond_wait()以锁定的互斥体返回,因此您必须解锁互斥体以允许在完成后在其他地方使用它。无论发生了回报,因为条件变量是信号与否是不相关的。您仍然需要检查您的谓词,而不考虑潜在的虚假唤醒。互斥锁的目的不是保护条件变量;它是为了保护条件变量被用作信号机制的谓词。这是 pthread 条件变量及其互斥锁最常被误解的习惯用法。条件变量不需要互斥保护;谓词数据确实如此。将谓词视为由条件变量/互斥对的用户监视的外部状态。
For example, a trivial yet obviously wrongpiece of code to wait for a boolean flag fSet:
例如,一段微不足道但明显错误的代码等待布尔标志fSet:
bool fSet = false;
int WaitForTrue()
{
while (!fSet)
{
sleep(n);
}
}
I should be obvious the main problem is the predicate, fSet, is not protected at all. Manythings can go wrong here. Ex: From the time you evaluate the while-conditon until the time you begin waiting (or spinning, or whatever) the value may have changed. If that change notification is somehow missed, you're needlessly waiting.
我应该很明显,主要问题是谓词, fSet, 根本不受保护。很多事情都可能在这里出错。例如:从您评估 while 条件到您开始等待(或旋转,或其他)时,该值可能已更改。如果不知何故错过了该更改通知,您将不必要地等待。
We can change this a little so at least the predicate is protected somehow. Mutual exclusion in both modifying andevaluating the predicate is easily provided with (what else) a mutex.
我们可以稍微改变一下,这样至少谓词以某种方式受到保护。修改和评估谓词时的互斥很容易通过(还有什么)互斥体提供。
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
bool fSet = false;
int WaitForTrue()
{
pthread_mutex_lock(&mtx);
while (!fSet)
sleep(n);
pthread_mutex_unlock(&mtx);
}
Well, that seems simple enough.. Now we never evaluate the predicate without first getting exclusive access to it (by latching the mutex). But this is still a major problem. We latched the mutex, but we never release it until our loop is finished. If everyone else plays by the rules and waits for the mutex lock before evaluation or modification of fSet, they're never be able to do so until we give up the mutex. The only "someone" that can do that in this case is us.
嗯,这看起来很简单。现在我们永远不会在没有首先获得对它的独占访问(通过锁存互斥锁)的情况下评估谓词。但这仍然是一个主要问题。我们锁住了互斥锁, 但在循环完成之前我们永远不会释放它。如果其他人都遵守规则并在评估或修改 之前等待互斥锁锁定fSet,那么在我们放弃互斥锁之前,他们永远无法这样做。在这种情况下,唯一可以做到这一点的“某人”就是我们。
So what about adding still more layers to this. Will this work?
那么如何为此添加更多层呢?这会起作用吗?
pthread_mutex_t mtx = PTHREAD_MUTEX_INITIALIZER;
bool fSet = false;
int WaitForTrue()
{
pthread_mutex_lock(&mtx);
while (!fSet)
{
pthread_mutex_unlock(&mtx);
// XXXXX
sleep(n);
// YYYYY
pthread_mutex_lock(&mtx);
}
pthread_mutex_unlock(&mtx);
}
Well, yes it will "work", but still is not much better. The period between XXXXXand YYYYYwe don't own the mutex (which is ok, since we're not checking or modifying fSetanyway). But anytime during that period some other thread can (a) obtain the mutex, (b) modify fSet, and (c) release the mutex, and we won't know a thing about it until we finish our sleep(), once-again obtain the mutex lock, and loop around for another check.
嗯,是的,它会“工作”,但仍然好不到哪里去。之间的时间段XXXXX和YYYYY我们不拥有互斥锁(没关系,因为我们没有检查或修改fSet)。但是在此期间的任何时候,其他线程都可以 (a) 获取互斥锁,(b) 修改fSet,以及 (c) 释放互斥锁,并且在我们完成我们sleep()的 再次获取互斥锁之前我们将一无所知锁定,然后循环进行另一次检查。
There hasto be a better way. Somehow there should be a way that we can release the mutex andbegin waiting for some sort of signal that tells us a change in the predicate may have happened. Equally important, when we receive that signal and return to our code, we should already own the lock that grants us access to check the predicate data. This is exactlywhat a condition-variable is designed to provide.
有有是一个更好的办法。不知何故,我们应该有一种方法可以释放互斥锁并开始等待某种信号,告诉我们谓词可能发生了变化。同样重要的是,当我们收到该信号并返回到我们的代码时,我们应该已经拥有允许我们检查谓词数据的锁。这正是条件变量旨在提供的。
The Condition Variable In Action
作用中的条件变量
Enter the condition-variable + mutex pair. The mutex protects access to changing or checkingthe predicate, while the condition variable sets up a system of monitoring a change, and more importantly, doing so atomically(as far as you're concerned, anyway) with the predicate mutual exclusion:
输入条件变量 + 互斥对。互斥锁保护对更改或检查谓词的访问,而条件变量设置了一个监控更改的系统,更重要的是,通过谓词互斥以原子方式(就您而言,无论如何)这样做:
int WaitForPredicate()
{
// lock mutex (means:lock access to the predicate)
pthread_mutex_lock(&mtx);
// we can safely check this, since no one else should be
// changing it unless they have the mutex, which they don't
// because we just locked it.
while (!predicate)
{
// predicate not met, so begin waiting for notification
// it has been changed *and* release access to change it
// to anyone wanting to by unlatching the mutex, doing
// both (start waiting and unlatching) atomically
pthread_cond_wait(&cv,&mtx);
// upon arriving here, the above returns with the mutex
// latched (we own it). The predicate *may* be true, and
// we'll be looping around to see if it is, but we can
// safely do so because we own the mutex coming out of
// the cv-wait call.
}
// we still own the mutex here. further, we have assessed the
// predicate is true (thus how we broke the loop).
// take whatever action needed.
// You *must* release the mutex before we leave. Remember, we
// still own it even after the code above.
pthread_mutex_unlock(&mtx);
}
For some other thread to signal the loop above, there are several ways to do it, the two most popular below:
对于其他一些线程来向上面的循环发出信号,有几种方法可以做到,下面是最流行的两种:
pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_mutex_unlock(&mtx);
pthread_cond_signal(&cv);
Another way...
其它的办法...
pthread_mutex_lock(&mtx);
TODO: change predicate state here as needed.
pthread_cond_signal(&cv);
pthread_mutex_unlock(&mtx);
Each has different intrinsic behavior and I invite you to do some homework on those differences and determine which is more appropriate for specific circumstances. The former provides better program flow at the expense of introducing potentiallyunwarranted wake-ups. The latter reduces those wake-ups but at the price of less context synergy. Eitherwill work in our sample, and you can experiment with how each affects your waiting loops. Regardless, one thing paramount, and bothmethods fulfill this mandate:
每个人都有不同的内在行为,我邀请您针对这些差异做一些功课,并确定哪种更适合特定情况。前者提供了更好的程序流程,但代价是引入了潜在的不必要的唤醒。后者减少了这些唤醒,但以减少上下文协同为代价。两者都适用于我们的示例,您可以试验每种方法如何影响您的等待循环。无论如何,有一件事情是最重要的,这两种方法都完成了这一任务:
Never change, nor check, the predicate condition unless the mutex is locked. Ever.
除非互斥锁被锁定,否则永远不要更改或检查谓词条件。曾经。
Simple Monitor Thread
简单的监控线程
This type of operation is common in a monitorthread that acts on a specific predicate condition, which (sans' error checking) typically looks something like this:
这种类型的操作在对特定谓词条件起作用的监视器线程中很常见,它(sans 的错误检查)通常看起来像这样:
void* monitor_proc(void *pv)
{
// acquire mutex ownership
// (which means we own change-control to the predicate)
pthread_mutex_lock(&mtx);
// heading into monitor loop, we own the predicate mutex
while (true)
{
// safe to check; we own the mutex
while (!predicate)
pthread_cond_wait(&cv, &mtx);
// TODO: the cv has been signalled. our predicate data should include
// data to signal a break-state to exit this loop and finish the proc,
// as well as data that we may check for other processing.
}
// we still own the mutex. remember to release it on exit
pthread_mutex_unlock(&mtx);
return pv;
}
A More Complex Monitor Thread
更复杂的监视器线程
Modifying this basic form to account for a notificationsystem that doesn't require you to keep the mutex latched once you've picked up the notification becomes a little more involved, but not by very much. Below is a monitor proc that does not keep the mutex latched during regular processing once we've established we've been served (so to speak).
修改此基本形成以占有通知系统,不要求你保持锁定一旦你拿起通知互斥成为一个涉及多一点,但不是很大。下面是一个监视器过程,一旦我们确定我们已经得到服务(可以这么说),它就不会在常规处理期间保持互斥锁锁存。
void* monitor_proc(void *pv)
{
// acquire mutex ownership
// (which means we own change-control to the predicate)
pthread_mutex_lock(&mtx);
// heading into monitor loop, we own the predicate mutex
while (true)
{
// check predicate
while (!predicate)
pthread_cond_wait(&cv, &mtx);
// some state that is part of the predicate to
// inform us we're finished
if (break-state)
break;
// TODO: perform latch-required work here.
// unlatch the mutex to do our predicate-independant work.
pthread_mutex_unlock(&mtx);
// TODO: perform no-latch-required work here.
// re-latch mutex prior to heading into wait
pthread_mutex_lock(&mtx);
}
// we still own the mutex. remember to release it on exit
pthread_mutex_unlock(&mtx);
return pv;
}
Where would someone use something like that? Well, suppose your "predicate" is the "state" of a work queue as well as some flag to tell you to stop looping and exit. Upon receiving the notification that something is "different", you check to see if you should continue executing your loop, and deciding you should continue, pop some data off the queue. Modifying the queue requires the mutex be latched (remember, its "state" is part of our predicate). Once we have popped our data, we have it locally and can process it independentof the queue state, so we release the mutex, do our thing, then require the mutex for the next go-around. There are many ways to code the above concept, including judicious use of pthread_cond_broadcast, etc. But the basic form is hopefully understandable.
哪里会有人使用类似的东西是?好吧,假设您的“谓词”是工作队列的“状态”以及一些告诉您停止循环并退出的标志。在收到某些“不同”的通知后,您检查是否应该继续执行循环,并决定应该继续,从队列中弹出一些数据。修改队列需要锁存互斥锁(记住,它的“状态”是我们谓词的一部分)。一旦我们弹出我们的数据,我们就在本地拥有它并且可以独立于队列状态处理它,所以我们释放互斥锁,做我们的事情,然后在下一次复飞时需要互斥锁。有很多方法可以对上述概念进行编码,包括明智地使用pthread_cond_broadcast等。
This turned out to be considerably longer than I had hoped, but this is a majorhurdle for people learning pthread-programming, and I feel it is worth the extra time/effort. I hope you got something out of it.
结果证明这比我希望的要长得多,但这是人们学习 pthread 编程的一个主要障碍,我觉得额外的时间/努力是值得的。我希望你能从中有所收获。
回答by Daij-Djan
yes it unlocks, waits for the condition to be fulfilled and then waits till it can reaquire the passed mutex.
是的,它解锁,等待条件满足,然后等待它可以重新获取传递的互斥锁。

