The boost mutex,condition_variable is very useful. But on Linux, boost actually does a series of packages for pthread_mutex_t and pthread_cond_t. Therefore, we can realize the convenience that boost brings to us again through the realization of the mutex,cond of the POSIX of the original ecology.
1. What is a mutex?
The mutex is essentially a lock that locks the mutex before accessing the shared resource, releasing the lock on the mutex after the access is complete. When the mutex is locked, any other thread that attempts to lock the mutex again will be blocked until the current thread releases the mutex. If there are multiple threads blocking when the mutex is released, the blocking thread on the mutex becomes ready, and the first thread that becomes running can lock the mutex, and the other thread is blocked, waiting for the next running state.
Pthread_mutex_t is the implementation of POSIX for mutexes.
Name of function |
Parameters |
Description |
Pthread_mutex_init |
pthread_mutex_t * Mutex, constpthread_mutex_t *attr |
Initializes a mutex that can be initialized directly using Pthread_mutex_initializer. |
Pthread_mutex_destroy |
pthread_mutex_t *mutex |
Releases the resources assigned to the mutex. Note that Pthread_mutex_init may have malloc resources. |
Pthread_mutex_lock |
pthread_mutex_t *mutex |
If the mutex is locked, the calling thread blocks until the mutex is unlocked |
Pthread_mutex_trylock |
pthread_mutex_t *mutex |
Lock, if failure does not block |
Pthread_mutex_unlock |
pthread_mutex_t *mutex |
Unlock |
Initialize using the init function:
[CPP]View Plaincopy
- #include <pthread.h>
- pthread_mutex_t Foo_mutex;
- void Foo ()
- {
- Pthread_mutex_init (&foo_mutex, NULL);
- Pthread_mutex_lock (&foo_mutex);
- /* do work . * /
- Pthread_mutex_unlock (&foo_mutex);
- Pthread_mutex_destroy (&foo_mutex);
- }
Of course the initialization
[CPP]View Plaincopy
- Pthread_mutex_init (&foo_mutex, NULL);
Foo_mutex can only be initialized once before use, and finally destroy. Initializing a mutex that has already been initialized will result in undefined behavior.
Another way to use:
[CPP]View Plaincopy
- pthread_mutex_t Foo_mutex = Pthread_mutex_initializer;
- void Foo ()
- {
- Pthread_mutex_lock (&foo_mutex);
- /* do work . * /
- Pthread_mutex_unlock (&foo_mutex);
- }
Of course, both of these usages have a problem: If exception is present before the lock is unlock, the lock will never unlock. In this case, you need to guard this resource. The specific reference to the implementation of Boost::mutex::scoped_lock is very simple but greatly simplifies the safe use of mutexes.
2. What is a conditional variable
Unlike mutexes, conditional variables are used to wait instead of locking. A condition variable is used to automatically block a thread until a particular situation occurs. Usually the condition variable and the mutex are used together.
Condition variables allow us to sleep and wait for a certain condition to appear. A conditional variable is a mechanism for synchronizing a global variable shared between threads, which consists of two actions: one thread waits for the condition variable to be set up, and the other thread causes the condition to be set.
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 signals to the associated condition variable, wakes one or more threads waiting for it, re-obtains the mutex, and re-evaluates the condition. If two processes share read-write memory, the condition variable can be used to implement thread synchronization between the two processes.
The initialization of conditional variables is similar to the initialization of a mutex, and there are two ways:
Pthread_cond_tmy_condition=pthread_cond_initializer;
You can also use the function Pthread_cond_init to initialize dynamically.
An introduction to each of the functions below.
function name |
Parameters |
Description |
pthread_cond_init |
pthread_cond_t *cond, Const pthread_condattr_t *attr |
Initialize |
Pthread_cond_destroy |
pthread_cond_t *cond |
recycle |
Pthrea D_cond_wait |
pthread_cond_t *cond, pthread_mutex_t *mutex |
Wait, no timeout |
pthr Ead_cond_timedwait |
pthread_cond_t *cond,pthread_mutex_t *mutex, const struct TIMESPEC *abstime |
Wait, there is a timeout |
pthread_cond_signal |
pthread_cond_t *cond |
A thread that is blocked on the same condition variable will be unlocked. If multiple threads are blocking at the same time, the scheduling policy determines the thread that receives the notification |
pthread_cond_broadcast |
pthread_cond_t *cond |
All threads that are blocked on this condition variable are notified. Once awakened, the thread will still require a mutex. |
A simple example of thread synchronization using conditional variables:
[CPP]View Plaincopy
- #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,thread2, (void *) NULL); /*create thread t_a*/
- Pthread_create (&t_b,null,thread1, (void *) NULL); /*create thread t_b*/
- Pthread_join (T_b, NULL); /*wait for exit of t_b*/
- Pthread_join (T_a, 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 ("Thread1 running, i =%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 running, i =%d\n", i);
- Pthread_mutex_unlock (&mutex);
- Sleep (1);
- }
- }
Output:
[CPP]View Plaincopy
- Thread1 running, i = 1
- Thread1 running, i = 2
- Thread2 running, i = 3
- Thread1 running, i = 4
- Thread1 running, i = 5
- Thread2 running, i = 6
- Thread1 running, i = 7
- Thread1 running, i = 8
- Thread2 running, i = 9
3. Producer-Consumer Realization
Producer Consumer Issues (English:producer-consumer problem), also known as limited buffering problems (English:bounded-buffer problem), is a classic case of a multithreaded synchronization problem. The problem describes two threads that share fixed-size buffers-the so-called "producer" and "consumer"-problems that can occur when they actually run. The primary role of the producer is to generate a certain amount of data into the buffer, and then repeat the process. At the same time, consumers consume the data in buffers. The key to this issue is to ensure that producers do not add data when the buffer is full, and consumers do not consume data when the buffer is empty.
[CPP]View Plaincopy
- #include <stdio.h>
- #include <stdlib.h>
- #define MAX 5
- pthread_mutex_t mutex = Pthread_mutex_initializer; / * Initialize the mutex * /
- pthread_cond_t cond = Pthread_cond_initializer; / * Initialize condition variable * /
- typedef struct{
- Char Buffer[max];
- int how_many;
- }buffer;
- BUFFER share={"", 0};
- Char ch=' A '; /* Initialize ch*/
- void *producer (void *);
- void *consumer (void *);
- int main (void)
- {
- pthread_t T_read;
- pthread_t T_write;
- Pthread_create (&t_write,null,producer, (void *) NULL); / * Create process t_a*/
- Pthread_create (&t_read,null,consumer, (void *) NULL); / * Create process t_b*/
- Pthread_join (T_write, (void * *) NULL);
- Pthread_join (T_read, NULL);
- Exit (0);
- }
- void *producer (void *junk)
- {
- int n=0;
- printf ("producer:starting\n");
- While (ch!=' K ')
- {
- Pthread_mutex_lock (&mutex); / * Lock the mutex * /
- if (Share.how_many!=max)
- {
- share.buffer[share.how_many++]=ch++; / * Write letters to cache * /
- printf ("Producer:put char[%c]\n", ch-1); /* Print Write Letter * /
- if (Share.how_many==max)
- {
- printf ("producer:signaling full\n");
- Pthread_cond_signal (&cond); / * Send a signal if the letter in the cache reaches the maximum value * /
- }
- }
- Pthread_mutex_unlock (&mutex); / * Unlock Mutex * /
- }
- Sleep (1);
- printf ("producer:exiting\n");
- return NULL;
- }
- void *consumer (void *junk)
- {
- int i;
- int n=0;
- printf ("consumer:starting\n");
- While (ch!=' K ')
- {
- Pthread_mutex_lock (&mutex); / * Lock the mutex * /
- printf ("\nconsumer:waiting\n");
- while (Share.how_many!=max)/* If the buffer letter is not equal to the maximum value, wait * /
- Pthread_cond_wait (&cond,&mutex);
- printf ("consumer:getting buffer::");
- For (i=0;share.buffer[i]&&share.how_many;++i,share.how_many--)
- Putchar (Share.buffer[i]); / * Loop Output Buffer Letter * /
- Putchar (' \ n ');
- Pthread_mutex_unlock (&mutex); / * Unlock Mutex * /
- }
- printf ("consumer:exiting\n");
- return NULL;
- }
Output: producer:starting
Producer:put Char[a]
Producer:put Char[b]
Producer:put Char[c]
Producer:put Char[d]
Producer:put Char[e]
Producer:signaling full
Consumer:starting
Consumer:waiting
Consumer:getting Buffer:: ABCDE
Consumer:waiting
Producer:put Char[f]
Producer:put Char[g]
Producer:put Char[h]
Producer:put Char[i]
Producer:put Char[j]
Producer:signaling full
Consumer:getting Buffer:: Fghij
Consumer:exiting
Producer:exiting
Source: http://blog.csdn.net/anzhsoft/article/details/19044069
http://blog.csdn.net/anzhsoft2008/article/category/2123999
POSIX uses mutexes and conditional variables to implement producer/consumer issues