Concurrent Learning: A discussion of conditional variables (condition variable)

Source: Internet
Author: User
Tags mutex posix semaphore

from:http://blog.csdn.net/fengge8ylf/article/details/6896380

Author: Wang Dong

1.1 What is conditional variable and condition wait.

To put it simply:

A condition variable (condition variable) is a mechanism for synchronizing with global variables shared between threads, consisting mainly of two actions: one thread waits for a condition to be true, suspends itself, another thread makes the condition, and notifies the waiting thread to continue. To prevent competition, the use of conditional variables is always combined with a mutex.

The definitions in the wiki are as follows:

Conceptually a condition variable is a \ A queue of threads, associated with a monitor, on which a thread. E condition to become true. Thus Each condition variable c is associated with a assertion P. While a thread was waiting on a condition variable, which is not considered to occupy the monitor, and then other Threa DS may enter the monitor to change the monitor ' s state. In most types of monitors, these are threads may signal the condition variable C to indicate so assertion P is true in the current state [1].

A condition variable (condition variable) is a special synchronization variable, which is the thread queue associated with a mutex (monitor), and the condition variable is associated with an assertion (assertion) p because one thread in the thread queue waits for the assertion p to be true. When a thread is in a wait condition variable (condition variable), the thread no longer uses the mutex (monitor), allowing other threads to enter the mutex to change the condition state.

There are two basic operations on a condition variable:

L Waiting (Wait): A thread is waiting on the condition variable for the assertion (assertion) p to be true, at which point the thread will not occupy the mutex (monitor);

L Notification (signal/notify): Another thread notifies the condition variable when it makes the assertion (assertion) p true.

When one thread is signal, another thread is activated, and the mutex (monitor) that two threads occupy, choose which thread to occupy the mutex, which is divided into blocking condition Variables (giving priority to the thread being notified) and nonblocking condition variables (giving priority to the thread that emits the signal notification [1].

Use conditional wait like the following scenario:

Multithreading accesses resources within a mutually exclusive zone, and the thread waits until the other thread frees the resource, and the thread continues, if there is not enough condition for the resource to be obtained. For example:

Thread1:

Lock (Mutex)

While (condition is false) {

Why use a while instead of if?

The problem of reference 1.2.1 condition variable

cond_wait (Cond, mutex, timeout)

}

DoSomething ()

Unlock (Mutex)

Thread2:

Lock (Mutex)

. ..

Condition is true

cond_signal (Cond)

Unlock (Mutex)

For example, Thread1 gets a link from a 50-size link pool, and if the already used link reaches 50, that thread must wait for a condition. Thread2 when you finish using a link, return the link to the link pool, and then send the condition notify and tell Thread1 to continue. 1.1.1 About condition variables (condition variable) and semaphores (semaphore)

A semaphore (semaphore) is a non-negative integer counter that is used for synchronization and mutual exclusion between processes or threads.

Through the semaphore can realize the "PV operation" This process or the synchronization mechanism between threads.

P operation is to obtain resources, the value of the semaphore minus 1, if the result is not negative then continue to execute, the thread to obtain resources, otherwise the thread is blocked, sleep, until the waiting resource is released by another thread;

The V operation is to release the resource, add 1 to the semaphore value, and release a thread waiting for the p operation to be performed.

In the simplest form, the value of a semaphore can only be 0 or 1, similar to a mutex.

When the semaphore value is any non-negative (greater than 1), its value represents the number of available resources.

Semaphores Semaphore and mutexes (mutexes) can be implemented to achieve synchronization and protection of a pool. Use a mutex to implement synchronization, using semaphore to implement the resource count.

The thread that gets the resource:

sem_wait (semaphore1)

Lock (Mutex)

. ..

Unlock (Mutex)

sem_post (Semaphore2)

The thread that freed the resource:

sem_wait (Semaphore2)

Lock (Mutex)

. ..

Unlock (Mutex)

sem_post (semaphore1)

This model is much like a multithreaded producer and consumer model, where the semaphore2 is designed to prevent excessive release.

Conditional variables can achieve more complex wait conditions than semaphores. Of course, conditional variables and mutexes can also implement semaphore functions (the Condition Variables under window only implement thread synchronization and cannot implement process synchronization).

In the posix.1 rationale, the article claims that mutexes and conditional variables also provide semaphores because "the main purpose of this standard is to provide a way of synchronizing between processes; These processes may or may not share the memory area." Mutexes and condition variables are described as synchronization mechanisms between threads that always share (a) memory area. Both are synchronized methods that have been widely used for many years. Each group of primitives is particularly suited to specific problems. While the intent of semaphores is to synchronize between processes, mutexes and condition variables are intended to be synchronized between threads, but semaphores can also be used between threads, and mutexes and condition variables can also be used between processes. Decisions should be taken on the basis of actual circumstances. The most useful scenario for semaphores is to indicate the number of available resources [11].

The personal feeling is: Due to the different origins, led to two ideas, a concept of the force of the condition variable (condition variable), that the signal is not what to use (for example, the POSIX thread model does not have the concept of semaphores, although also proposed POSIX semaphore, But why not put it together in the first place? Another idea is just the opposite (for example, the concept of a conditional variable at the beginning of a window, only the concept of a semaphore).

In the future, both Linux and Windows have both.

The conditional wait functions in 1.2 Linux are those.

Linux provides conditional wait functions and notify functions.

L pthread_cond_timedwait(cond, mutex, abstime);

L pthread_cond_wait(cond, mutex);

L pthread_cond_signal(cond); At least one thread will be unlocked (a thread that is blocked on a condition variable).

L pthread_cond_broadcast(COND): The line threads unlocked that will be blocked on the condition variable.

Thread 1 calls pthread_cond_wait () to do three parts:

1. Unlock the mutex at the same time,

2. And wait for condition cond to occur

3. After receiving the notice, lock the mutex;

After calling Pthread_cond_wait (), unlock the mutex at the same time and wait for the condition cond to occur ( requires unlocking and blocking is an atomic operation )

Now that the mutex has been unlocked, other threads can enter the mutex area and modify the condition.

At this point, the pthread_cond_wait () call has not returned. Wait condition Mycond is a blocking operation, which means that the thread will sleep and will not consume CPU cycles until it wakes up. Until certain conditions occur [3].

Suppose another thread 2 locks the mutex, changes the condition, and then invokes the function pthread_cond_signal () to activate the wait condition. This means that thread 1 will now wake up. Thread 1 attempts to lock the mutex , because thread 2 has not yet unlocked the mutex, so thread 1 has only wait, and thread 1 takes precedence over the mutex lock, and then it can do what it wants.

Here's the problem: How to get thread 1 to give priority to mutex locking instead of other threads, Pthread_mutex_lock's pseudocode [4] shows the possibility of this implementation, in which the thread in wait is first activated in the signal function.

Pthread_cond_wait (Mutex, cond):

Value = cond->value;

Pthread_mutex_unlock (mutex);

Pthread_mutex_lock (Cond->mutex);

if (value = = Cond->value) {

Me->next_cond = cond->waiter;

Cond->waiter = Me;

Pthread_mutex_unlock (Cond->mutex);

Unable_to_run (me);

} else

Pthread_mutex_unlock (Cond->mutex);

Pthread_mutex_lock (mutex);

Pthread_cond_signal (COND):

Pthread_mutex_lock (Cond->mutex);

cond->value++;

if (cond->waiter) {

Sleeper = cond->waiter;

Cond->waiter = sleeper->next_cond;

Able_to_run (sleeper);

}

Pthread_mutex_unlock (Cond->mutex);

The following example shows the example code using a condition variable [2]:

One or more threads are responsible for an increase in count number (Inc_count), and another thread is responsible for listening for count numbers, and is reporting (watch_count) once it reaches Count_limit.

void Inc_count (void) {

...

Pthread_mutex_lock (&count_mutex);

count++;

if (count = = Count_limit) {

pthread_cond_signal (&COUNT_THRESHOLD_CV);

printf ("Inc_count (): Thread%ld, Count =%d Threshold reached./n",

MY_ID, Count);

}

printf ("Inc_count (): Thread%ld, Count =%d, unlocking mutex/n",

MY_ID, Count);

Pthread_mutex_unlock (&count_mutex);

...

}

void Watch_count (void) {

...

Pthread_mutex_lock (&count_mutex);

while (Count<count_limit) {

pthread_cond_wait (&COUNT_THRESHOLD_CV, &count_mutex);

printf ("Watch_count (): Thread%ld Condition signal received./n", my_id);

Count + 125;

printf ("Watch_count (): Thread%ld count now =%d./n", my_id, Count);

}

Pthread_mutex_unlock (&count_mutex);

...

the problem exists in the 1.2.1 condition variable: false wakeup

What is mentioned in the Help in Linux:

Under multi-core processors, pthread_cond_signal may activate more than one thread (a thread that blocks on a condition variable). On a multi-processor, it may is impossible for a implementation of pthread_cond_signal () to avoid the unblocking of than one thread blocked on a condition variable.

As a result, when a thread calls Pthread_cond_signal (), Multiple threads calling pthread_cond_wait () or pthread_cond_timedwait () are returned. This effect becomes " false Awakening " (Spurious wakeup) [4]

The effect is this more than one thread can return from it call to Pthread_cond_wait () or pthread_cond_timedwait () as a R Esult of one Call to Pthread_cond_signal (). This effect is called "spurious wakeup". Note that the situation is self-correcting into that the number of threads, are so awakened is finite; For example, the next thread to call Pthread_cond_wait () after the sequence of events above blocks.

Although false arousal can be solved in the pthread_cond_wait function, it is not worthwhile to reduce the edge condition (fringe condition) in order to have a low probability of occurrence. Correcting this problem reduces the concurrency of all the more advanced synchronization operations that are based on it. So pthread_cond_wait's implementation did not solve it.

While this problem could being resolved, the loss of efficiency for a fringe condition then occurs only rarely is unacceptabl E, especially given that one has to check the predicate associated with a condition variable. Correcting this problem would unnecessarily reduce the degree of concurrency to this basic building to all higher-l Evel synchronization operations.

So the usual standard solution is this:

Change the condition's judgment from if to while

The while () in pthread_cond_wait not only checks the condition variable before waiting for the condition variable, but also checks the condition variable after waiting for the condition variable.

In this way, the condition to make a more judgment, you can avoid "false awakening."

This is why a while loop should be added before pthread_cond_wait () to determine if the condition is false.

Interestingly, this problem also exists almost everywhere, including the description of Linux condition waiting, POSIX threads Description, window API (condition variable), Java, and so on.

L The description of the condition variable in the help of Linux is [4]:

The practice of adding a while check is considered to increase the robustness of the program, and spurious wakeup is considered permissible in IEEE Std 1003.1-2001.

An added benefit of allowing spurious wakeups was that applications are forced to code a predicate-testing-loop around the Condition wait. This also makes the application tolerate superfluous condition broadcasts or signals on the same condition variable that M AY is coded in some and the other part of the application. The resulting applications are thus more robust. Therefore, IEEE STD 1003.1-2001 explicitly documents, spurious wakeups may occur.

L in POSIX threads [5]:

David R. Butenhof that conditional competition in multi-core systems (race condition [8]) led to the occurrence of false wakes and that the complete elimination of false wakes essentially reduced the operational performance of conditional variables.

"..., but on some multiprocessor systems, making condition wakeup completely predictable might substantially slow all condit Ion variable operations. The race conditions that cause spurious wakeups should is considered "

L in Window's condition variable [6]:

As described in MSDN Help, the spurious wakeups problem persists and conditions require duplicate check.

Condition variables are subject to spurious wakeups (those no associated with a explicit wake) and stolen Wakeups (Anoth Er thread manages to run before the woken thread). Therefore, you should recheck a predicate (typically into a while loop) after a-sleep operation returns.

L in Java [7], the wait is written as follows:

Synchronized (obj) {

while (<condition does not hold>)

Obj.wait ();

...///Perform action appropriate to condition

}

Effective Java has mentioned item 50:never invoke wait outside a loop.

It is clear that false awakening is a problem, but it was also clarified in the revision of JDK5 of JLS's third edition. Update in Javadoc for JDK 5

A thread can also wake up without being notified, interrupted, or timing out, a so-called spurious wakeup. While this is rarely occur in practice, applications must guard against it by testing for the condition that should caused the thread to being awakened, and continuing to wait if the condition is not satisfied. In the other words, waits should always occur in loops.

Apparently, the spurious wakeup is a issue (I doubt this it is a OK known issue) that intermediate to expert developers Know it can happen but it just has been clarified in JLS third the edition which has been revised as part of JDK 5 developmen T. Javadoc of Wait method in JDK 5 has also been updated

1.3 &

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.