Linux Programming Learning notes----thread synchronization condition variables for multithreaded programming

Source: Internet
Author: User
Tags mutex

Reprint Please specify source: http://blog.csdn.net/suool/article/details/38582521.

Basic concepts and principles

Mutexes can resolve mutually exclusive access to resources, but in some cases, mutual exclusion does not solve the problem, such as two of threads need to mutually exclusive processing of their own operations, but a single thread of operation is only one condition to be executed, once the missed is not reproducible, because the threads compete with each other for CPU resources, Therefore, when the condition is established, the thread does not necessarily compete for the CPU and is missed, resulting in never being executed ....

Therefore, a mechanism is needed to solve this problem, and more importantly, only one situation of the thread is required to perform the operation, and the application of resources to the resource is wasted, while Linux provides the conditional variable plus mutex to solve the problem.

The condition variable variable is also derived from the POSIX threading Standard, another thread synchronization mechanism. Used primarily to wait for a condition to occur. Can be used to synchronize individual threads in the same process. Of course, if a condition variable is stored in a memory area shared by multiple processes, it is also possible to synchronize between processes through a conditional variable.

Each condition variable is always associated with a mutex, and the condition itself is protected by a mutex, and the thread must lock the mutex between changing the condition state. The advantage of a condition variable with respect to the mutex is that it allows the thread to wait for the condition to occur in a non-competitive manner. When a thread obtains a mutex, it finds itself waiting for a condition to become true, and if so, the thread can wait on a condition so that it does not need to be polled to determine the addition, greatly saving CPU time.

In the mutex article said: The mutex is used for locking, not for waiting ; Now this sentence can be enhanced as: The mutex is used for locking, the condition variable is used for waiting ;

The condition variable is declared as the pthread_cond_t data type and has a specific definition in <bits/pthreadtypes.h>.

Basic Operationsconditional variable initialization and destruction

/* Initialize condition variable  */int pthread_cond_init (pthread_cond_t *__restrict __cond,   //pointer to the variable to initialize                              __const pthread_condattr_t *__restrict __cond_attr);//Properties/* Destroy condition variable */int pt<span style= "font -size:12px; " >hread_cond_destroy (pthread_cond_t *__cond);</span>
the above two functions are initialized and destroyed by the conditional variables respectively.

As with the initialization of the mutex, if the condition variable is statically assigned, it can be initialized by a constant, as follows:

<span style= "FONT-SIZE:12PX;" >pthread_cond_t Mlock = pthread_cond_initializer;</span>
It can also be initialized with pthread_cond_init () , which can only be initialized in this way for dynamically assigned conditional variables that cannot be initialized directly by assigning values. When you do not need to use a condition variable, you need to call Pthread_cond_destroy () to destroy the resource that the condition occupies. property settings for a condition variable
/* Initialize Condition Variable Property object  */int pthread_condattr_init (pthread_condattr_t *__attr);/* Destroy Condition Variable Property object  */int pthread_condattr _destroy (pthread_condattr_t *__attr);/* Gets the identity of the condition variable Property object that is shared between processes  */int pthread_condattr_getpshared (__const pthread_condattr_t * __restrict __attr,                                        int *__restrict __pshared);/* Set the Condition Variable Property object to identify whether it is shared between processes */int pthread_condattr _setpshared (pthread_condattr_t *__attr, int __pshared);

The setting of this property is the same as the mutex property setting, which can be used to refer to the use of mutexes:property settings for mutexes。
Request for a condition variable use

/<span style= "FONT-FAMILY:SIMSUN;FONT-SIZE:12PX;" >*  Wait condition becomes true */int pthread_cond_wait (pthread_cond_t *__restrict __cond,                              pthread_mutex_t *__restrict __mutex ); /* Timed Wait condition is true */int pthread_cond_timedwait (pthread_cond_t *__restrict __cond,                                   pthread_mutex_t *__restrict __mutex,< c6/>__const struct Timespec *__restrict __abstime); /* wakes up a waiting condition for the thread.  */int pthread_cond_signal (pthread_cond_t *__cond); /* Wake all threads waiting for the condition */int pthread_cond_broadcast (pthread_cond_t *__cond);</span>
(1) the pthread_cond_wait () function is used to wait for the condition to be triggered. The function passes two parameters, a condition variable a mutex, the function associates the condition variable with the mutex, the mutex protects the condition, and the incoming mutex must be locked. After calling the Pthread_cond_wait () function, the following two actions are performed by the Atom :

    • Put the calling thread on the list of threads waiting for the condition, i.e. go to sleep;
    • Unlocking the mutex;

Because of these two operations, the atomic operation turns off the time channel between the condition check and the thread going to sleep wait condition change, so that no condition changes are missed.

When pthread_cond_wait () returns, the mutex is locked again.

(2) the pthread_cond_timedwait () function and the pthread_cond_wait () work in a similar way, just one more wait time. The structure of the wait time is the struct timespec,

<span style= "FONT-SIZE:12PX;" >    struct timespec{      time_t  tv_sec    //seconds.      Long    tv_nsec   //nanoseconds.      };  </span>

The function requires that the time value passed in is an absolute value, not a relative, for example, to wait for 3 minutes, you must first obtain the current time, and then add 3 minutes.

To get the Timespec value of the current system time, there is no directly callable function, you need to call the Gettimeofday function to get the TIMEVAL structure, and then convert to the TIMESPEC structure, the conversion formula is:

<span style= "FONT-SIZE:12PX;" >timespec.tv_sec = Timeval.tv_sec;timespec.tv_nsec = timeval.tv_usec * 1000;</span>

so to wait 3 minutes, the TIMESPEC time structure should be obtained as follows:
<span style= "FONT-SIZE:12PX;" >    struct timeval now;      struct TIMESPEC until;      Gettimeofday (&now);//Get system Current time            //convert time from Timeval structure to TIMESPEC structure      until.tv_sec = now.tv_sec;      Until.tv_nsec = Now.tv_usec *;            Increase min      until.tv_sec + = 3 *;  </span>

If the condition does not occur after the time, the Etimedout error is returned.

When successfully returning from Pthread_cond_wait () and pthread_cond_timewait (), the thread needs to recalculate the condition because other threads may have changed the condition during the run.

(3) pthread_cond_signal () & Pthread_cond_broadcast ()

Both of these functions are used to send a wake-up signal to the waiting thread, and the pthread_cond_signal () function wakes only one thread that waits for the condition, and pthread_cond_broadcast () broadcasts a change in the condition state to wake up all the threads waiting for the condition. For example, multiple threads read-only shared resources, which is the ability to wake them all up.

It is important to note that it is important to send a signal to the thread after changing the condition state.

One candidate for sending and broadcasting a conditional variable signal is to insist on using broadcast to send. Unicast is used for this case only if the waiting code is written exactly, and only one of the waiting persons needs to wake up, and which thread wakes up, so this situation uses a unicast, so all other cases must be sent using broadcast.

using the example

The following program uses conditional variables and mutexes to implement producer consumer issues. The entire temporary storage space is 2. Therefore, if the temporary space is full, the production process is blocked, and if no product is blocking the consumer thread.

The application has requested three objects:

1) A mutex object that is used with the condition variable

2) A space non-null conditional variable that the consumer thread waits for when there is no product in space; the producer notifies this variable after the product has been generated

3) A space non-full conditional variable, the generation thread waits for this condition variable when the space is full; consumer threads notify this variable after consuming the product


The line flow is as follows:

1. Apply for mutexes If the mutex locks, blocking waits

2. Whether the test space is full

3. If the condition satisfies (not full), performs the operation, unlocks the mutex after completion

4. If the second step is not satisfied, block, wait for the non-full condition variable

The consumer thread is as follows:

1. Apply for mutex, if locked, block wait

2. Test if the space is empty

3. Satisfy non-null, then perform operation, unlock after completion

4. If the second step is not satisfied, block the current process and wait for the space non-null variable.

The source code is as follows:

/*************************************************************************> File name:pthread_cond_exp.c> Author:suool > mail:[email protected] | | [email protected]> Website:http://blog.csdn.net/suool | http://suool.net> Created time:2014 August 15 Friday 13:27 13 seconds > Description: *************************************** /#include <stdio.h> #include <stdlib.h> #include <time.h># Include <pthread.h> #define Buffer_size 2/* Circular BUFFER of integers.      */struct prodcons {int buffer[buffer_size];         /* The actual data */pthread_mutex_t lock;        /* Mutex ensuring exclusive access to buffer */int readpos, Writepos;      /* Positions for reading and writing */pthread_cond_t notempty;       /* Signaled when buffer was not empty */pthread_cond_t notfull; /* Signaled when buffer was not full */};/* Initialize a buffer */void init (struct prodcons *prod) {Pthread_mutex_init (& Amp;prod->loCk,null);  Initialize the mutex lock Pthread_cond_init (&prod->notempty,null);   Initializes the condition variable pthread_cond_init (&prod->notfull,null);    ..... prod->readpos = 0;                        Prod->writepos = 0; Initialize read-write operation location}/* Store An integer in the buffer */void put (struct prodcons * prod, int data)//Input product sub-function {Pthread_mutex       _lock (&prod->lock); Lock Mutex/* Wait until buffer is not full * * while ((Prod->writepos + 1)% Buffer_size = = prod->readpos)//test        The test space is full {printf ("Producer wait for not full\n");  Pthread_cond_wait (&prod->notfull, &prod->lock);     Wait space is empty}/* Write the data and advance write pointer */PROD-&GT;BUFFER[PROD-&GT;WRITEPOS] = data;                        Write Data prod->writepos++;    Write position plus an if (Prod->writepos >= buffer_size)//write to tail, return prod->writepos = 0; /*signal that the buffer was now not empty */pthread_cond_signal (&prod->notempty); Send a data signal   Pthread_mutex_unlock (&prod->lock);    Unlock}/* Read and remove an integer from the buffer */int get (struct prodcons *prod) {int data;       Pthread_mutex_lock (&prod->lock);        Lock/* Wait until buffer is not empty */while (Prod->writepos = = prod->readpos)//test for data {        printf ("Consumer wait for not empty\n"); Pthread_cond_wait (&prod->notempty, &prod->lock);     Empty wait}/* Read the data and advance read pointer * */data = prod->buffer[prod->readpos];                        Read Data prod->readpos++;          Read position plus one if (prod->readpos >= buffer_size) prod->readpos = 0;  Read to the tail, back to/* Signal that the buffer was now not full */pthread_cond_signal (&prod->notfull);      Notification of non-full pthread_mutex_unlock (&prod->lock); Unlock return data;} #define OVER ( -1) struct prodcons buffer;/*-------------------------------producer-----------------------*/void * Producer (void* data) {int n;        for (n = 0; n < 5; n++)//production of the first five products {printf ("producer Sleep 1 second......\n");      Sleep (1);        Produce one printf per second ("Put the%d product\n", n);    Put (&buffer, n);        } for (n=5; n<10; n++)//After production of five {printf ("producer Sleep 3 second......\n");              Sleep (3);        Three printf per three seconds ("Put the%d product\n", n);    Put (&buffer,n);    } put (&buffer, over);    printf ("producer stopped!\n"); return NULL;}    /*--------------------------Consumer----------------------------*/void * Consumer (void * data) {int d=0;        while (1) {printf ("Consumer sleep 2 second......\n");             Sleep (2);        Consumes one d=get per 2 seconds (&buffer);        printf ("Get the%d product\n", d);        D = Get (&buffer);    if (d = = over) break;    } printf ("Consumer stopped!\n"); return NULL;} /*----------------------------producer--------------------------*/int Main (int Argc,char *Argv[]) {pthread_t th_a, th_b;    Thread definition void * retval;    Init (&buffer);     Pthread_create (&th_a, NULL, producer, 0);       Create production line Pthread_create (&th_b, NULL, consumer, 0); Consumer thread/* Wait until producer and consumer finish.    */Pthread_join (th_a, &retval);              Pthread_join (Th_b, &retval); Wait for thread to end return 0;}

The results are as follows:


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.