1. First, the definition of pthread_cond_wait is as follows:
The pthread_cond_wait ()AndPthread_cond_timedwait ()Functions are used to block on a condition variable. They are calledMutexLocked by the calling thread or undefined behaviour will result.
These functions atomically releaseMutexAnd cause the calling thread to block on the condition variableCond; Atomically here means "atomically with respect to access by another thread to the mutex and then the condition variable ". that is, if another thread is able to acquire the mutex after the about-to-block thread has released it, then a subsequent callPthread_cond_signal ()OrPthread_cond_broadcast ()In that thread behaves as if it were issued after the about-to-block thread has blocked.
2. the above explanation shows that pthread_cond_wait () must be used together with pthread_mutex.
The pthread_cond_wait () function automatically releases mutex once it enters the wait status.
In thread1:
Pthread_mutex_lock (& m_mutex );
Pthread_cond_wait (& m_cond, & m_mutex );
Pthread_mutex_unlock (& m_mutex );
In thread2:
Pthread_mutex_lock (& m_mutex );
Pthread_cond_signal (& m_cond );
Pthread_mutex_unlock (& m_mutex );
Why should I use it with pthread_mutex? This is to prevent thread 1 from calling pthread_cond_wait () But thread 1 has not entered the wait cond State. At this time, thread 2 calls cond_singal. If the mutex lock is not used, the cond_singal will be lost. When a lock is added, thread 2 can call cond_singal only when mutex is released (that is, pthread_cod_wait () enters the wait_cond state and automatically releases mutex.
3.Pthread_cond_wait () will automatically lock mutex once wait successfully obtains the cond condition.
This causes another problem. This is because
The pthread_cond_wait ()AndPthread_cond_timedwait ()Is a cancellation point.
In thread3:
Pthread_cancel (& m_thread );
Pthread_join ();
BecausePthread_cond_wait ()AndPthread_cond_timedwait ()Is the point function of the thread exit, so in thread3
You can call pthread_cancel () to exit thread 1. Then it is clear that thread 1 will exit between pthread_cond_wait (& m_cond, & m_mutex); and pthread_mutex_unlock (& m_mutex);. After the pthread_cond_wait () function returns, mutex is automatically locked, at this time, thread 1 exits (and does not run to pthread_mutex_unlock (). If thread2 does not get the lock status at this time.
The solution to this problem is usually as follows/* Focus 1 */
Void Cleanup(Void* Arg)
{
Pthread_mutex_unlock (& amp; mutex );
}
Void* Thread1 (Void* Arg)
{
Pthread_cleanup_push (Cleanup, Null );// Thread cleanup Handler
Pthread_mutex_lock (& amp; mutex );
Pthread_cond_wait (& amp; cond, & amp; mutex );
Pthread_mutex_unlock (& amp; mutex );
Pthread_cleanup_pop (0);
}
In Linux, multi-threaded programming will certainly encounter situations where conditional variables are required. In this case, you must use the pthread_cond_wait () function. However, the execution process of this function is hard to understand.
The workflow of pthread_cond_wait () is as follows (taking example in man as an example ):
Consider two shared variables X and Y, protected by the mutex Mut, and a condition vari-
Able cond that is to be signaled whenever x becomes greater than Y.
Int X, Y;
Pthread_mutex_t mut = pthread_mutex_initializer;
Pthread_cond_t cond = pthread_cond_initializer;
Waiting until X is greater than Y is already med as follows:
Pthread_mutex_lock (& MUT );
While (x <= y ){
Pthread_cond_wait (& cond, & MUT );
}
/* Operate on x and y */
Pthread_mutex_unlock (& MUT );
Modifications on X and Y that may cause X to become greater than y shoshould signal the con-
Dition if needed:
Pthread_mutex_lock (& MUT );
/* Modify x and y */
If (x> Y) pthread_cond_broadcast (& Cond );
Pthread_mutex_unlock (& MUT );
In this example, the two threads need to modify the values of X and Y. The first thread suspends when x <= y, it is not executed until x> Y (the value of X and Y may be modified by the second thread, and the first thread is awakened when x> Y ), that is, first initialize a normal mutex mut and a condition variable cond. Then execute the following function bodies in the two threads respectively:
Pthread_mutex_lock (& MUT );
While (x <= y ){
Pthread_cond_wait (& cond, & MUT );
}
/* Operate on x and y */
Pthread_mutex_unlock (& MUT );
And: pthread_mutex_lock (& MUT);
/* modify x and y */
If (x> Y) pthread_cond_signal (& Cond );
pthread_mutex_unlock (& MUT);
In fact, the function execution process is very simple. When the first thread runs to pthread_cond_wait (& cond, & MUT, if X is <= Y, the mut mutex is unlocked , and the cond condition variable is locked , the first thread is suspended (no CPU cycle is occupied ).
In the second thread, the Mut is blocked because it is locked by the first thread. At this time, the Mut can be locked because it has been released, and modify the values of X and Y. After the modification, an if statement determines whether it is x> Y. If yes, then pthread_cond_signal () the function will wake up the first thread and release muts in the next sentence. Then the first thread starts executing from pthread_cond_wait (). First, lock mut again. If the lock succeeds, then, judge the conditions ( /* Focus 2 */ as to why the while clause is used, that is, Judge again after being awakened, cause Analysis). If conditions are met, the system will be awakened for processing, and release muts .
As to why Condition determination should be performed again after being awakened (that is, why the while loop is used to determine the condition ),/* Focus 2 */This is because there may be a "group shock effect ". Some people think that, since it is awakened, it must meet the conditions. In fact, it is not. If multiple threads are waiting for this condition,At the same time, there can only be one thread for processing. At this time, it is necessary to make another conditional judgment.To enable only one thread to enter the critical section for processing. For this, let's look at the following:
Reference POSIX rationale:
Condition wait Semantics
It is important to note that when pthread_cond_wait () and pthread_cond_timedwait () return without error, the associated predicate may still be false. similarly, when pthread_cond_timedwait () returns with the timeout error, the associated predicate may be true due to an unavoidable race between the expiration of the timeout and the predicate state change.
The application needs to recheck the predicate on any return because it cannot be sure there is another thread waiting on the thread to handle the signal, and if there is not then the signal is lost. the burden is on the application to check the predicate.
Some implementations, maid on a multi-processor, may sometimes cause multiple threads to wake up when the condition variable is signaled simultaneously on different processors.
In general, whenever a condition wait returns, the thread has to re-evaluate the predicate associated with the condition wait to determine whether it can safely proceed, showould wait again, or shoshould declare a timeout. A return from the wait does not imply that the associated predicate is either true or false.
It is thus recommended that a condition wait be enclosed in the equivalent of a "while loop" that checks the predicate.
We can see from the above:
1. pthread_cond_signal may wake up multiple threads at the same time on a multi-processor. When you have only one thread to process a task, other awakened threads need to continue.Wait: the meaning of the while loop is shown here.,In addition, the specification requires pthread_cond_signal to wake up at least one thread on pthread_cond_wait.In fact, some implementations will wake up on a single processor for simplicity.Multiple threads.
2,Some applications, such as the thread pool, pthread_cond_broadcast wake up all threadsBut we usually only need some threads to execute the task, soOther threads need to continue wait.Therefore, we strongly recommend that you use the while loop here.
To put it simply, pthread_cond_signal () may also wake up multiple threads. If you allow only one thread to access at the same time, you must use while for conditional judgment, to ensure that only one thread is processing in the critical section.
In addition:
/*********** Pthread_cond_wait **********/
Pthread_mutex_lock (& qlock);/* Lock */
Pthread_cond_wait (& qready, & qlock );/* Block --> unlock -->Wait ()Return --> lock */
Pthread_mutex_unlock (& qlock);/* unlock */
/*************************************** **************/
The thread will sleep until a specific condition occurs. During this period, no busy queries that waste CPU time will occur. From the thread point of view, it is only waiting for the pthread_cond_wait () call to return.
Initialization and cleanup
A condition variable is a real data structure to be initialized.
First, define or assign a condition variable, as shown below:
Then, call the following function for initialization:
Pthread_cond_init (& mycond, null ); |
Look, Initialization is complete! You need to destroy a condition variable before releasing it, as shown below:
Pthread_cond_destroy (& mycond ); |
Send signals and broadcast
Pay attention to sending signals and broadcasts. If the thread changes some shared data and wants to wake up all the waiting threads, use pthread_cond_broadcast to call it, as shown below:
Pthread_cond_broadcast (& mycond ); |
In some cases, the active thread only needs to wake up the first sleeping thread. Assume that you have added only one job to the queue. You only need to wake up a job.ProgramThread (it is impolite to wake up other threads again !) :
Pthread_cond_signal (& mycond ); |
This function only wakes up one thread. If POSIX thread standards allow you to specify an integer, you can wake up a certain number of sleeping threads, which is more perfect. Unfortunately, I was not invited to the meeting.