Thread synchronization--condition variables

Source: Internet
Author: User
Tags posix

1. There is a problem with the mutex:

mutexes are the necessary tools for threaded threads, but they are not omnipotent. For example, what happens if a thread is waiting for a condition in the shared data to appear? It can repeatedly lock and unlock mutex objects, checking the shared data structure each time to find a value. But this is a waste of time and resources, and the efficiency of this busy query is very low.

Between each check, you can let the calling thread go to sleep briefly, such as sleep for three seconds, but the thread code cannot respond as quickly as possible. What is really needed is a way to put a thread to sleep when it waits for certain conditions to be met. Once the condition is met, the thread waking up to sleep waiting for a specific condition is awakened. If you can do this, the thread code will be very efficient and will not consume valuable mutex locks. That's what POSIX condition variables can do!

2. Condition variables:

Conditional variables compensate for the lack of mutexes by allowing threads to block and wait for another thread to send a signal, which is often used in conjunction with mutexes. When used, a condition variable is used to block a thread, and when the condition is not met, the thread often unlocks the corresponding mutex and waits for the condition to change. Once another thread changes the condition variable, it notifies the corresponding condition variable to wake one or more threads that are being blocked by this condition variable. These threads will re-lock the mutex and re-test whether the condition is satisfied.

3. Related functions of condition variables

(1) Create and unregister

Conditional variables, like mutexes, have both static and dynamic methods of creation.

A. Static mode

Static mode uses the Pthread_cond_initializer constant, as follows:
pthread_cond_t Cond=pthread_cond_initializer

B. Dynamic approach
int Pthread_cond_init (pthread_cond_t *cond, pthread_condattr_t *cond_attr)

Initializes the condition variable cond with the property specified by Cond_attr, using the default property when Cond_attr is null. The Linuxthreads implementation condition variable does not support attributes, so the cond_attr parameter is actually ignored.


C. Write-off

int Pthread_cond_destroy (pthread_cond_t *cond)

unregistering A condition variable calls Pthread_cond_destroy () to unregister the condition variable only if no thread is waiting on the condition variable, otherwise it returns EBUSY. Because the condition variables implemented by Linux do not have any resources assigned to them, the logoff action includes checking for waiting threads only.

(2) Waiting and excitation

A. Waiting

int pthread_cond_wait (pthread_cond_t *cond, pthread_mutex_t *mutex)
Understanding the role of pthread_cond_wait () is very important-it is the core of the POSIX threading signaling system and the most incomprehensible part.

First, let's consider the following scenario: The thread locks the mutex object for viewing the linked list, but the list happens to be empty. This particular thread can do nothing-it was designed to remove nodes from the list, but now there are no nodes. Therefore, it can only:

When a mutex object is locked, the thread calls Pthread_cond_wait (&mycond,&mymutex). The pthread_cond_wait () call is quite complex, so we only perform one operation at a time.

The first thing pthread_cond_wait () does is to unlock the mutex at the same time (so that other threads can modify the linked list) and wait for the condition Mycond to occur (so that when pthread_cond_wait () receives a "signal" from another thread, It will wake up). Now that the mutex is unlocked, the other threads can access and modify the linked list, and the item may also be added.

At this point, the pthread_cond_wait () call has not yet returned. Unlocking a mutex occurs immediately, but the wait condition Mycond is usually a blocking operation, which means that the thread will sleep and will not consume CPU cycles until it wakes up. This is exactly what we expect to happen. The thread will sleep until a specific condition occurs, and during this time no busy queries are wasted on the CPU. From the thread's point of view, it is just waiting for the pthread_cond_wait () call to return.

Now, let's say that another thread (called "line Line 2") locks the Mymutex and adds an entry to the linked list. After unlocking the mutex, the Line 2 thread calls the function Pthread_cond_broadcast (&mycond) immediately. After this operation, line Line 2 will cause all threads waiting for the mycond condition variable to wake up immediately. This means that the first thread (still in a pthread_cond_wait () call) will now wake up.

Now, take a look at what happened to the first thread. You might think that after the call to Pthread_cond_broadcast (&mymutex) on line Line 2, the pthread_cond_wait () of line Line 1 will return immediately. Not like that! In fact, pthread_cond_wait () will perform the last action: re-lock Mymutex. Once pthread_cond_wait () locks the mutex object, it returns and allows line Line 1 to continue execution. At that point, it can check the list immediately to see what changes it is interested in.

Stop and Review!

The process is very complicated, so let's review it first. The first thread is called first:
Pthread_mutex_lock (&mymutex);

Then, it checks the list. Did not find something of interest, so it called:
Pthread_cond_wait (&mycond, &mymutex);


The pthread_cond_wait () call then performs a number of operations before returning:
Pthread_mutex_unlock (&mymutex);

It unlocks the Mymutex and then goes to sleep, waiting for Mycond to receive the POSIX thread "signal." Once the "signal" is received (quoted because we are not talking about a traditional UNIX signal, but rather a signal from the pthread_cond_signal () or pthread_cond_broadcast () call), it will wake up. But pthread_cond_wait () does not return immediately-it has to do one more thing: Re-lock the mutex:
Pthread_mutex_lock (&mymutex);

Pthread_cond_wait () knew we were looking for a change in the Mymutex "behind", so it went ahead and locked the mutex for us before returning.

int pthread_cond_timedwait (pthread_cond_t *cond, pthread_mutex_t *mutex, const struct TIMESPEC *abstime)

Like Pthread_cond_timedwait and Pthread_cond_wait, the mutex and wait condition variables are automatically unlocked, but it also limits the wait time. If the cond does not fire within the time specified by Abstime, the mutex mutex is re-locked and an error etimedout is returned. The Abstime parameter specifies an absolute time at which the time origin is the same as that of gettimeofday: Abstime = 0 for January 1, 1970 00:00:00 GMT.

For example, to wait for 5 seconds, this process:
struct Timeval now;
struct TIMESPEC timeout;

Gettimeofday (&now);
Timeout.tv_sec = now.tv_sec + 5;
timeout.tv_nsec = now.tv_usec * 1000;

which

struct timeval {

time_t tv_sec;

suseconds_t tv_usec;

};

struct timespec {
time_t tv_sec;
Long tv_nsec;
};

B. Inspire

int pthread_cond_signal (pthread_cond_t *cond);
int Pthread_cond_broadcast (pthread_cond_t *cond);

There are two forms of the excitation condition, pthread_cond_signal () activates a thread that waits for the condition, and when multiple threads block on this condition variable, which thread is awakened by the thread's scheduling policy; Pthread_cond_broadcast () All waiting threads are activated, and these threads are awakened to compete for the corresponding mutex again.

It is important to note that the activation function must be protected with a mutex that protects the condition variable, otherwise the condition satisfies the signal that it may be emitted between the test condition and the call pthread_cond_wait () function, resulting in an unrestricted wait.

4. Example

A, set up two threads 1, 2, two threads to access the shared resources, and add 1 operations, when the shared resource <=3, thread 1 hangs do not operate, then thread 2 work, shared resources >3, both work.

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>
#include <errno.h>

int gnum = 0;
pthread_mutex_t Mutex;
pthread_cond_t cond;

static void Pthread_func_1 (void);
static void pthread_func_2 (void);

int main (void)
{
pthread_t pt_1 = 0;
pthread_t pt_2 = 0;
int ret = 0;

Pthread_mutex_init (&mutex, NULL);
Pthread_cond_init (&cond, NULL);

ret = pthread_create (&pt_1, NULL, (void *) pthread_func_1, NULL);
if (ret! = 0)
{
Perror ("Pthread_1_create");
}

ret = pthread_create (&pt_2, NULL, (void *) pthread_func_2, NULL);
if (ret! = 0)
{
Perror ("Pthread_2_create");
}

Pthread_join (pt_1, NULL);
Pthread_join (pt_2, NULL);

printf ("Main programme exit!\n");
return 0;
}

static void Pthread_func_1 (void)
{
int i = 0;

for (;;)
{
printf ("This is pthread1!\n");
Pthread_mutex_lock (&mutex);

Note that this is the preemption of the perimeter to cause one thread to access the mutex multiple times while another thread is sleep, so sleep is called after the mutex is obtained

Sleep (1);

Condition variables, when gnum<=3, thread 1 hangs and unlocks itself, allowing thread 2 to go in

while (Gnum <= 3) {
Pthread_cond_wait (&cond, &mutex);
}

Thread 1 restarts here when Thread 2 calls pthread_cond_signal (&cond)
Critical resources

gnum++;
printf ("Thread1 add one to num:%d\n", gnum);
Pthread_mutex_unlock (&mutex);
}
}

static void pthread_func_2 (void)
{
int i = 0;

for (;;)
{
printf ("This is pthread2!\n");
Pthread_mutex_lock (&mutex);

Note that this is the preemption of the perimeter to cause one thread to access the mutex multiple times while another thread is sleep, so sleep is called after the mutex is obtained
Sleep (1);

Critical resources
gnum++;
printf ("Thread2 add one to num:%d\n", gnum);

When gnum = = 4 o'clock, trigger
if (Gnum = = 4)
Pthread_cond_signal (&cond);

Pthread_mutex_unlock (&mutex);
}
Pthread_exit (0);
}

B

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>

pthread_mutex_t mutex = Pthread_mutex_initializer;
pthread_cond_t cond = Pthread_cond_initializer;

void *thread1 (void *);
void *thread2 (void *);

int i=1;


int main (void)
{
pthread_t t_a;
pthread_t T_b;

Pthread_create (&t_a,null,thread1, (void *) NULL);
Pthread_create (&t_b,null,thread2, (void *) NULL);
Pthread_join (T_b, NULL);
Pthread_mutex_destroy (&mutex);
Pthread_cond_destroy (&cond);
Exit (0);
}

void *thread1 (void *junk)
{
for (i=1;i<=9;i++)
{
Pthread_mutex_lock (&mutex);
if (i%3==0)
Pthread_cond_signal (&cond);
Else
printf ("thead1:%d\n", I);
Pthread_mutex_unlock (&mutex);


Sleep (1);
}
}

void *thread2 (void *junk)
{
    while (i<=9)
    {
    pthread_mutex_lock (&mutex);
  
    if (i%3!=0)
         Pthread_cond_wait (&cond,&mutex);
    printf ("thread2:%d\n", I);
    pthread_mutex_unlock (&mutex);
  
  sleep (1);
 } 
}

     program created a 2 new threads enable them to run synchronously, implementing a process t_b print 10 within t_a print other numbers, program start thread t_b does not meet conditional waits, thread t_a run make a Loop plus 1 and print. Until i for 3 In multiples of , thread t_a sends signal notification process t_b , then t_b satisfies the conditions, prints i value.

Here is the result of the operation:

#cc –lpthread–o Cond COND.C

#./cond

Thread1:1

Thread1:2

Thread2:3

Thread1:4

Thread1:5

Thread2:6

Thread1:7

Thread1:8

Thread2:9

Thread synchronization--condition variables

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.