POSIX condition Variables
int Pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr); int Pthread_cond_destroy (pthread_cond_t * cond); int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex); int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime); int pthread_cond_signal (Pthread_ cond_t *cond); int pthread_cond_broadcast (pthread_cond_t *cond);
Unlike mutexes, conditional variables are used to wait instead of locking . The condition variable is used to automatically block the calling thread until the conditions required by the condition variable occur. Usually the condition variables need to be used in conjunction with the mutex, and the condition variables are protected by mutual exclusion .
The condition detection is performed under the protection of the mutex. If a condition is false, a thread automatically blocks and releases the mutex that waits for the state to change . If another thread changes the condition, it sends a signal to the associated condition variable, wakes one or more threads waiting on the condition variable, and the threads regain the mutex and re-evaluate the condition. If you put a condition variable in shared memory, and the two processes can share read and write memory, the condition variable can be used to implement thread synchronization between two processes.
Condition Variable Usage Specification
1. Wait for the condition code
Pthread_mutex_lock (&mutex), while (condition is false) { pthread_cond_wait (&cond, &mutex);} Modify Condition Pthread_mutex_unlock (&mutex);
/** Explanation: Why use while instead of if?
Man-page gives the answer: If a signal is delivered to a thread waiting for a condition variable, and upon return from
The signal handler the thread resumes waiting for the condition variable as if it is not interrupted, or
it shall return zero due To spurious wakeup.
That is, if a thread that is waiting for a condition variable receives a signal, the thread should wait for the condition variable to be returned from the signal processing function as if it had not been interrupted, or be falsely awakened to return 0. If this is the case, then in fact the condition has not been changed, then if you do not continue to judge the condition of the true and false to continue to execute, the modification conditions will be problematic, so you need to use the while loop to judge again, if the condition or false must continue to wait.
Note: In multiprocessor systems, pthread_cond_signal may wake up multiple waiting threads, which is also a spurious wakeup.
**/
2. Send the signal code to the condition
Pthread_mutex_lock (&mutex), set the condition to True pthread_cond_signal (&cond);p thread_mutex_unlock (&mutex);
Condition Variable API Description
1.pthread_cond_init
Initialize before using conditional variables: You can generate and initialize a condition variable in a single statement such as:
pthread_cond_t my_condition=pthread_cond_initializer;//for inter-process thread communication;
or using function Pthread_cond_init to initialize dynamically;
2.pthread_cond_destroy
The function can be used to destroy the specified condition variable, and the resources allocated to it will be freed. The process calling the function does not require waiting on the condition variable specified by the parameter;
3.pthread_cond_wait && pthread_cond_timedwait
Three things to do in cond_wait primitives:
(1) unlocking the mutex;
(2) wait for the condition until the thread sends him a notice;
(3) When wait returns, re-lock the mutex;
The first parameter, cond, is a pointer to a condition variable. The second parameter mutex is a pointer to the associated mutex.
The difference between a function pthread_cond_timedwait function type and a function pthread_cond_wait is that timedwait has a timeout, the timeout value is how long we are willing to wait, if it reaches or exceeds the referenced parameter *abstime, It will end blocking and return error etime.
The TIMESPEC structure is as follows: struct timespec{ time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */};
Note: This time value is an absolute number instead of a relative, for example, assuming that you are willing to wait three seconds, then instead of converting 3 seconds into a TIMESPEC structure, you need to convert the current practice to 3 minutes to TIMESPEC structure, the function that gets the current time value can be clock_ GetTime (we use this one) can also be gettimeofday.
4.pthread_cond_signal && Pthread_cond_broadcast
Cond_signal the actions that are done by the primitive:
A notification is made to the first thread waiting for the condition, and if no thread is in the state of the wait condition, the notification is ignored;
Cond_broadcast:
send a notification to all threads waiting on the condition;
The parameter cond is a pointer to a condition variable. When signal is called, a thread that is blocked on the same condition variable will be unlocked. If multiple threads are blocked at the same time, the scheduling policy determines the thread that receives the notification . If broadcast is called, all threads that are blocked on the condition variable are notified. Once awakened, the thread will still require a mutex . If no thread is currently waiting for notification, the above two calls actually become an empty operation, and the kernel ignores the notification of the condition variable (if the parameter *cond points to an illegal address, the return value einval);
Class Condition Encapsulation
//condition Class design class Condition{public:condition (const pthread_mutexattr_t *MUTEXATTR = NULL, const pthread_condattr_t *conda TTR = NULL); ~condition (); Conditional variable function int signal (); int broadcast (); int wait (); int timedwait (int seconds); Mutex function int lock (); int Trylock (); int unlock ();p rivate:pthread_mutex_t M_mutex; pthread_cond_t M_cond;};
Condition class Implementation Condition::condition (const pthread_mutexattr_t *mutexattr, const pthread_condattr_t *CO NDATTR) {//Initialize mutex Pthread_mutex_init (&m_mutex, mutexattr); Initialize the condition variable pthread_cond_init (&m_cond, condattr);} Condition::~condition () {//Destroy Mutex Pthread_mutex_destroy (&m_mutex); Destroy the condition variable Pthread_cond_destroy (&m_cond);} int condition::signal () {return pthread_cond_signal (&m_cond);} int Condition::broadcast () {return pthread_cond_broadcast (&m_cond);} int condition::wait () {return pthread_cond_wait (&m_cond, &m_mutex);} int condition::timedwait (int seconds) {//Gets the current time of the struct timespec abstime; Clock_gettime (Clock_realtime, &abstime); The current time plus the number of seconds to wait, constituting an absolute time value abstime.tv_sec + = seconds; Return pthread_cond_timedwait (&m_cond, &m_mutex, &abstime);} int Condition::lock () {return pthread_mutex_lock (&m_mutex);} int Condition::trylock () {return pthread_mutex_trylock (&m_mutex);} INT Condition::unlock () {return pthread_mutex_unlock (&m_mutex);}
producer consumer problem Unbounded buffer
/** implementation: We assume that the buffer is unbounded description: The producer can continue to produce, using the pthread_cond_signal when the notification, if there is no consumer thread waiting conditions, then this notification will be discarded, but also does not affect the overall code execution, No consumer thread is waiting, indicating that the product resources are sufficient, that is, while the judgment fails, will not enter the waiting state, direct consumption of products (i.e. modification conditions). **/const unsigned int producer_count = 5;//producer Number const unsigned int consumer_count = 3;//consumer number//Definition condition class condition cond ;//Buffer ~o (∩_∩) o~int nready = 0;//consumer void *consumer (void *args) {int id = * (int *) args; Delete (int *) args; while (true) {Cond.lock (); Lock the Mutex while (!) ( Nready > 0) {printf ("--Thread%d wait...\n", id); Cond.wait (); Wait for the condition variable} printf ("* * thread%d alive, and consume product%d ... \ n", id, Nready); --Nready; Consumption printf ("Thread%d end consume ... \ n", id); Cond.unlock (); Unlock the Mutex sleep (1); } pthread_exit (NULL);} producer void *producer (void *args) {int id = * (int *) args; Delete (int *) args; while (true) {Cond.lock (); Lock Mutex printf ("+ + thread%d signal, and PRODUCE Product%d ... \ n ", id, nready+1); + + Nready; Production cond.signal (); Send conditional variable signal printf ("Thread%d end produce, signal...\n\n", id); Cond.unlock (); Unlock the Mutex sleep (1); } pthread_exit (NULL);} int main () {pthread_t thread[producer_count+consumer_count]; First generate consumer for (unsigned int i = 0; i < Consumer_count; ++i) pthread_create (&thread[i], NULL, CONSUMER, NE w int (i)); Sleep (1); The producer waits for a period of time, accelerates the consumer wait event to generate//then generates producer for (unsigned int i = 0; i < Producer_count; ++i) pthread_create (& Thread[consumer_count+i], NULL, producer, new Int (i)); for (unsigned int i = 0; i < Producer_count+consumer_count; ++i) Pthread_join (Thread[i], NULL);}
Linux Multithreading Practice (8)--posix condition variables to solve the problem of producer consumers