Introduction:
The related functions are as follows:
1 int pthread_cond_init (pthread_cond_t * cond, pthread_condattr_t * cond_attr );
2 int pthread_cond_wait (pthread_cond_t * cond, pthread_mutex_t * mutex );
3 int pthread_cond_timewait (pthread_cond_t * cond, pthread_mutex * mutex, const timespec * abstime );
4 int pthread_cond_destroy (pthread_cond_t * Cond );
5 Int pthread_cond_signal (pthread_cond_t * Cond );
6 int pthread_cond_broadcast (pthread_cond_t * Cond); // unblock all threads
Brief description:
(1) Initialize. INIT () or pthread_cond_t cond = pthread_cond_initialier; set the attribute to null.
(2) Wait for the condition to be set. pthread_wait, pthread_timewait.wait () to release the lock, and block the wait for the condition variable to be true
Timewait () sets the wait time. If the wait time is not signal, etimeout is returned. (The lock ensures that only one thread is wait)
(3) activation condition variables: pthread_cond_signal, pthread_cond_broadcast (activate all waiting threads)
(4) Clear the condition variable: destroy; wireless process wait; otherwise, ebusy is returned.
Detailed description
1. Initialization:
The data type used by the condition variable is pthread_cond_t. Initialization is required before use. Two methods are available:
Use the pthread_cond_initializer constant in static mode, as follows:
Pthread_cond_t cond = pthread_cond_initializer
Dynamic: The pthread_cond_init function is used to clean up the memory space of the dynamic condition variable before it is released.
# Include <pthread. h>
Int pthread_cond_init (pthread_cond_t * restrict cond, pthread_condattr_t * restrict ATTR );
Int pthread_cond_destroy (pthread_cond_t * Cond );
If the call succeeds, 0 is returned. If the call fails, the error number is returned.
When the ATTR parameter of pthread_cond_init is null, a conditional variable of the default attribute will be created. It will be discussed after non-default conditions.
Although the POSIX standard defines attributes for condition variables, they are not implemented in linuxthreads. Therefore, the cond_attr value is usually null and ignored.
Blocking on the condition variable pthread_cond_wait
# Include <pthread. h>
Int pthread_cond_wait (pthread_cond_t * CV,
Pthread_mutex_t * mutex );
Returned value: 0 is returned if the function is successful. Any other returned values indicate an error.
The function will unlock the mutex lock pointed to by the mutex parameter and block the current thread on the condition variable pointed to by the CV parameter.
The blocked thread can be awakened by the pthread_cond_signal function, pthread_cond_broadcast function, or after the signal is interrupted.
The return of the pthread_cond_wait function does not mean that the condition value has changed. You must re-check the condition value.
When the pthread_cond_wait function returns, the corresponding mutex lock will be locked by the current thread, even if a function error is returned.
Generally, a condition expression is checked under the protection of a mutex lock. When the condition expression is not met, the thread will still block the condition variable. When another thread changes the condition value and sends a signal to the condition variable, wait for one or all threads on the condition variable to be awakened, then they attempt to occupy the corresponding mutex again.
After the thread on the condition variable is awakened, the value of the condition may change until the pthread_cond_wait () function returns. Therefore, after the function is returned, the condition value must be re-tested before the corresponding mutex lock is locked. The best test method is to call the pthread_cond_wait function cyclically and set the expressions that meet the condition to the termination condition of the loop. For example:
Pthread_mutex_lock ();
While (condition_is_false)
Pthread_cond_wait ();
Pthread_mutex_unlock ();
The order in which different threads blocked on the same condition variable are released is not certain.
Note: The pthread_cond_wait () function is the exit point. If a pending exit request exists when this function is called, and the thread can exit, this thread will be terminated and start executing the aftercare function, and the mutex lock related to the condition variable will remain locked.
3. Remove the blocking pthread_cond_signal on the condition variable.
# Include <pthread. h>
Int pthread_cond_signal (pthread_cond_t * cv );
Returned value: 0 is returned if the function is successful. Any other returned values indicate an error.
A function is used to release a thread that is blocked on a specified condition variable.
The corresponding conditional variables must be used under the protection of mutex. Otherwise, the unlock of the condition variable may occur before the condition variable is locked, resulting in a deadlock.
The sequence of all threads in the wake-up blocking condition variable is determined by the scheduling policy. If the thread scheduling policy is sched_other type, the system will wake up the thread based on the priority of the thread.
If no thread is blocked on the condition variable, calling pthread_cond_signal () will not work.
4. Blocking until the specified time pthread_cond_timedwait
# Include <pthread. h>
# Include <time. h>
Int pthread_cond_timedwait (pthread_cond_t * CV,
Pthread_mutex_t * MP, const structtimespec * abstime );
Returned value: 0 is returned if the function is successful. Any other returned values indicate an error.
When the function reaches a certain period of time, the blocking will be lifted even if the condition does not occur. This time is specified by the parameter abstime. When a function is returned, the corresponding mutex lock is often locked, even if a function error is returned.
Note: The pthread_cond_timedwait function also exits.
The timeout parameter is a time in a day. Example:
Pthread_timestruc_t;
To. TV _sec = Time (null) + timeout;
To. TV _nsec = 0;
The error code returned for timeout is etimedout.
5. Release all blocked threads pthread_cond_broadcast
# Include <pthread. h>
Int pthread_cond_broadcast (pthread_cond_t * cv );
Returned value: 0 is returned if the function is successful. Any other returned values indicate an error.
The function wakes up all threads blocked by the pthread_cond_wait function on a condition variable. The CV parameter is used to specify this condition variable. When no thread is blocked on this condition variable, the pthread_cond_broadcast function is invalid.
Because the pthread_cond_broadcast function wakes up all threads that are blocked on a condition variable, these threads will compete for the corresponding mutex lock again after being awakened, so you must use the pthread_cond_broadcast function with caution.
6. Release the condition variable pthread_cond_destroy.
# Include <pthread. h>
Int pthread_cond_destroy (pthread_cond_t * cv );
Returned value: 0 is returned if the function is successful. Any other returned values indicate an error.
Release the condition variable.
Note: the space occupied by the condition variable is not released.
7. Wakeup loss problems
Calling the pthread_cond_signal or pthread_cond_broadcast function may cause the loss of wake-up when the thread does not obtain the corresponding mutex lock.
Wake-up loss often occurs in the following situations:
One thread calls the pthread_cond_signal or pthread_cond_broadcast function;
The other thread is located between the test condition variable and the call of the pthread_cond_wait function;
No thread is in a blocked wait state.
Condition lock pthread_cond_t
Description,
Waiting thread
1. Apply a lock before using pthread_cond_wait.
2. Pthread_cond_wait will be unlocked internally, and then wait for the condition variable to be activated by other threads
3. Pthread_cond_wait is automatically locked after being activated
Activation thread:
1. Lock (use the same lock as the waiting thread)
2. Pthread_cond_signal
3. Unlock
The above three operations of the activation thread are within the pthread_cond_wait function of the waiting thread during the running time.
Others
Pthread_cond_wait () and pthread_cond_timedwait () are both implemented as cancellation points. Therefore, the thread waiting for this point will immediately run again and leave pthread_cond_wait () after re-locking mutex (), then, cancel the operation. That is to say, if pthread_cond_wait () is canceled, mutex remains locked. Therefore, you need to define the exit callback function to unlock it.
Example
Consider two shared variables X and Y, protected by the mutex Mut, and
A condition variable 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 saved 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
// Shocould signal the condition if needed:
Pthread_mutex_lock (& MUT );
/* Modify x and y */
If (x> Y) pthread_cond_broadcast (& Cond );
Pthread_mutex_unlock (& MUT );
/* If it can be proved that at most one waiting thread needs to be waken
Up (for instance, if there are only two threads communicating through X
And y), pthread_cond_signal can be used as a slightly more efficient
Alternative to pthread_cond_broadcast. in doubt, use
Pthread_cond_broadcast.
To wait for X to becomes greater than y with a timeout of 5 seconds,
Do:
*/
Struct timeval now;
Struct timespec timeout;
Int retcode;
Pthread_mutex_lock (& MUT );
Gettimeofday (& now );
Timeout. TV _sec = now. TV _sec + 5;
Timeout. TV _nsec = now. TV _usec * 1000;
Retcode = 0;
While (x <= Y & retcode! = Etimedout ){
Retcode = pthread_cond_timedwait (& cond, & Mut, & timeout );
}
If (retcode = etimedout ){
/* Timeout occurred */
} Else {
/* Operate on x and y */
}
Pthread_mutex_unlock (& MUT );
For more details, see man pthread_cond_wait.
----------------------------------------------------
Classic producer/consumer example.
# Include <pthread. h>
# Include <stdio. h>
# Include <stdlib. h>
# Define max 5
Pthread_mutex_t mutex = pthread_mutex_initializer;/* initialize the mutex lock */
Pthread_cond_t = pthread_code_initializer;/* initialize the condition variable */
Typedef struct {
Char buffer [Max];
Int how_many;
} Buffer;
Buffer share = {"", 0 };
Char CH = 'a';/* initialize Ch */
Void * read_some (void *);
Void * write_some (void *);
Int main (void)
{
Pthread_t t_read;
Pthread_t t_write;
Pthread_create (& t_read, null, read_some, (void *) null);/* create process T_A */
Pthread_create (& t_write, null, write_some, (void *) null);/* create process T_ B */
Pthread_join (t_write, (void **) null );
Pthread_mutex_destroy (& mutex );
Pthread_cond_destroy (& Cond );
Exit (0 );
}
Void * read_some (void * junk)
{
Int n = 0;
Printf ("R % 2D: starting/N", pthread_self ());
While (Ch! = 'Z ')
{
Pthread_mutex_lock (& lock_it);/* Lock mutex */
If (share. how_example! = Max)
{
Share. Buffer [Share. how_many ++] = CH ++;/* read letters into the cache */
Printf ("R % 2D: Got char [% C]/n", pthread_self (), CH-1);/* print read letter */
If (share. how_rows = max)
{
Printf ("R % 2D: signaling full/N", pthread_self ());
Pthread_cond_signal (& write_it);/* send a signal if the number of letters in the cache reaches the maximum value */
}
Pthread_mutex_unlock (& lock_it);/* unlock mutex */
}
Sleep (1 );
Printf ("R % 2D: exiting/N", pthread_self ());
Return NULL;
}
Void * write_some (void * junk)
{
Int I;
Int n = 0;
Printf ("w % 2D: starting/N", pthread_self ());
While (Ch! = 'Z ')
{
Pthread_mutex_lock (& lock_it);/* Lock mutex */
Printf ("/NW % 2D: waiting/N", pthread_self ());
While (share. how_timeout! = Max)/* If the cache area letters are not equal to the maximum value, wait */
Pthread_cond_wait (& write_it, & lock_it );
Printf ("w % 2D: Writing buffer/N", pthread_self ());
For (I = 0; share. Buffer [I] & share. how_many; ++ I, share. how_many --)
Putchar (share. Buffer [I]);/* Circular output cache letter */
Pthread_mutex_unlock (& lock_it);/* unlock mutex */
}
Printf ("w % 2D: exiting/N", pthread_self ());
Return NULL;
}
_______________________________________________________________________________________
After entering Q, you need to wait for the thread to wake up from sleep (from pending to running), that is, the thread will be joined after 10 s in the worst case. Disadvantages of using sleep: the thread cannot be awakened in time.
The pthread_cond_timedwait function is implemented as follows:
# Include <stdio. h>
# Include <sys/time. h>;
# Include <unistd. h>;
# Include <pthread. h>;
# Include <errno. h>;
Pthread_t thread;
Pthread_cond_t cond;
Pthread_mutex_t mutex;
Bool flag = true;
Void * thr_fn (void * Arg ){
Struct timeval now;
Struct timespec outtime;
Pthread_mutex_lock (& mutex );
While (FLAG ){
Printf (". \ n ");
Gettimeofday (& now, null );
Outtime. TV _sec = now. TV _sec + 5;
Outtime. TV _nsec = now. TV _usec * 1000;
Pthread_cond_timedwait (& cond, & mutex, & outtime );
}
Pthread_mutex_unlock (& mutex );
Printf ("thread exit \ n ");
}
Int main (){
Pthread_mutex_init (& mutex, null );
Pthread_cond_init (& cond, null );
If (0! = Pthread_create (& Thread, null, thr_fn, null )){
Printf ("error when create pthread, % d \ n", errno );
Return 1;
}
Char C;
While (C = getchar ())! = 'Q ');
Printf ("Now terminate the thread! \ N ");
Flag = false;
Pthread_mutex_lock (& mutex );
Pthread_cond_signal (& Cond );
Pthread_mutex_unlock (& mutex );
Printf ("wait for thread to exit \ n ");
Pthread_join (thread, null );
Printf ("Bye \ n ");
Return 0;
}
The waiting time is specified by the abstime parameter (absolute system time, timeout after this time), and The etimedout error code is returned. The wait time is not affected by the system clock change.
Although the time is specified by the second and the second, the system time is in milliseconds. According to the scheduling and priority reasons, the set time length should be more or less than expected. You can use the system clock interface gettimeofday () to obtain the timeval struct.
Note: To use conditional variables reliably and never forget to wake up conditional variables, A bool variable and mutex variable should be used in combination with the conditional variable. For example, this demo.
____________________________________________________________________________
Differences between conditional variables, mutex locks, and semaphores
1. The mutex lock must always be unlocked by the lock thread. When the semaphore is mounted, it does not need to be executed by the same process that has executed its waiting operation. One thread can wait for a given signal lamp, while the other thread can mount the signal lamp.
2. The mutex lock is either locked or unlocked (Binary state, type binary semaphore ).
3. Because a semaphore has a State associated with it (its Count value), the semaphore hanging-out operation is always remembered. However, when sending a signal to a condition variable, if no thread is waiting on the condition variable, the signal will be lost.
4. mutex lock is designed for locking. conditional variables are designed for waiting. signals can be used for locking or waiting, which may lead to more overhead and higher complexity.