3

By my understanding the pthread_cond_t is an signal object, similar to the Event on windows platform.

So the basic functionality of pthread_cond_t should be waiting for it and signal it. The interface should be as following:

int pthread_cond_wait(pthread_cond_t* cone);
int pthread_cond_singal(pthread_cond_t* cond);

But actually, the pthread_cond_wait need an mutex* type parameter which seams not directly related to its functionality. So you need an mutex even just want to create an signal for communication between threads, which doesn't access the same data at the same time.

So why the interface design as it, and eventually add overhead to the user?

Edit1: I know the mutex are used to protected the conditional data, but if design the interface without mutex, you can also acheive your goal by combine mutex and pthread_cond. And you can also just using pthread_cond to notify the other thread which doesn't have data shared between them.

For example, you can have an producer thread which create file, after finished, notify another consumer to process file, there is no data need to be protected by mutex.

ZijingWu
  • 3,350
  • 3
  • 25
  • 40
  • 1
    See http://stackoverflow.com/questions/2763714/why-do-pthreads-condition-variable-functions-require-a-mutex/18604957 as well. Condition variables are not similar to win32 Events. The (rather new) win32 equivalent is http://msdn.microsoft.com/en-us/library/windows/desktop/ms682052(v=vs.85).aspx – nos Oct 24 '13 at 10:12
  • @nos I was thrilled beyond words when that was added to the Windows API. Great links, btw. – WhozCraig Oct 24 '13 at 10:16
  • 1
    @ZijingWu pthread condition variables does not stay signaled. So your example of notifying a thread to process a file cannot be done without sharing data with pthread cond. e.g. you might notify the consumer thread before it has reached the code that waits for the condition, or if you notify it to process the 2. file, it might miss that since it is busy processing the first file. But the coupled mutex allows you to check for a shared variable that says that there are files that needs to be processed. The code can even avoid calling a lot of _cond_wait() and cond_signal() calls in such cases. – nos Oct 24 '13 at 10:37
  • Keep in mind that there are many other mechanisms available to you, to kick off your file processing thread you can use semaphores, or even a pipe(). – nos Oct 24 '13 at 10:38

2 Answers2

6

The fundamental reason for the mutex in a condition variable + mutex combination is to provide protection to the predicate data.

Read this carefully.

Condition variables are a signaling mechanism. That's all. The thing they signal you for is a prospective change in some external predicate condition that you, as a waiter, have subscribed to be interested in. When you are eventually awoken you own the mutex, and thus with it exclusive rights to the predicate data. This is vital. So long as all threads that need to access the predicate data play by the rules and no thread ever accesses the predicate data in any way without owning the underlying mutex, everything works.

The part that is noteworthy to you, the application developer, and is equally vital: The action of waiting on a condition variable atomically (as far as you're concerned, anyway) begins the wait and unlatches the mutex to allow other waiters access to obtain it, and therefore sanctioned access to the predicate data. Generic Windows events have nothing like this until Server 2008 and Vista). The closest thing I can describe how it would have to work on Windows is unlocking a hMutex and beginning to wait on an hEvent atomically, thereby eliminating the potential of change sneaking in between the two operations.

This is vital because it eliminates the race condition of a typical unprotected set-and-test. Said-race condition without the atomic unlatch-and-wait causes significant problems. Ex: you own the mutex, check the data, not what you need, so you unlock the mutex an wait for an event. It is conceivable that between the time you unlatch the mutex and actually begin the wait-operation the condition you're waiting on happens in that slice of time. And you missed it. That won't happen when properly waiting with a cvar-mtx combo.

Above all remember this. Condition variables don't hold "state" as you may think. The predicate state is held in data variables of your own design. Protecting that state is the primary job of the associated mutex. You don't need to own the predicate data mutex to signal a condition change. But you do need to own the mutex to actually make that change. If you don't, you're playing with fire.


EDIT: given the now-edited premise of the question (a signally mechanism only with no shared predicate data), I wouldn't use a condition variable + mutex combo in the first place. I'd use a blocking pipe and write a byte to it when the "signal" needed to be sent. And you can't design the interface with a coupled cvar+mutex "entity", as there are times when you want to change predicate data and NOT signal the prospective waiters. you can do that latching only the mutex and making the change without invoking the signal. Were they coupled, you wouldn't have that luxury.

WhozCraig
  • 65,258
  • 11
  • 75
  • 141
  • Would you expect the blocking pipe to be the most efficient solution on Linux? – user1055568 Mar 30 '15 at 20:22
  • @user1055568 waiting on a blocking pipe for a byte-write would be hard-pressed to be beaten either in efficiency or simplicity, though I'm not a kernel guy. The actual k-side of efficiency would be best answered by an expert in that arena. It has worked very well for me in the past on Linux and non-Linux platforms alike. – WhozCraig Mar 30 '15 at 21:20
  • Right, and if you want timeout, wrap in select() or epoll(), which I think is usually better than absolute timeout of pthreads wait. But, I'm not sure about performance. Pipes must support IPC, which seems like a heavier problem than between threads. – user1055568 Mar 30 '15 at 22:10
1

You premise is incorrect. You cannot sanely use a condition variable without a predicate protected by the mutex.

For example, you can have an producer thread which create file, after finished, notify another consumer to process file, there is no data need to be protected by mutex.

So you're suggesting this:

Producer:
1. Create file.
2. Signal condition variable.

Consumer:
1. Check for file.
2. If present, stop.
3. block on condition variable.
4. Go to step 1.

That can't work. What if the consumer finishes step 2 and then the producer does steps 1 and 2? The consumer will go to step 3 and wait for a signal that will never come. The signal is not "saved" because condition variables are stateless. You must maintain the state yourself, and since that state is necessarily shared, it must be protected by a mutex.

A common incorrect belief about pthread_cond_wait is that it is a conditional wait. It is not. it is an unconditional wait for a condition.

David Schwartz
  • 179,497
  • 17
  • 214
  • 278
  • Good specific example, when I ask this question I didn't know condition variable is stateless. And now I think the 'condition variable' name is a little bit miss leading, because variable should have state. – ZijingWu Mar 05 '14 at 00:03