POSIX uses mutexes and conditional variables to implement producer/consumer issues

Source: Internet
Author: User
Tags posix

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
    1. #include <pthread.h>
    2. pthread_mutex_t Foo_mutex;
    3. void Foo ()
    4. {
    5. Pthread_mutex_init (&foo_mutex, NULL);
    6. Pthread_mutex_lock (&foo_mutex);
    7. /* do work . * /
    8. Pthread_mutex_unlock (&foo_mutex);
    9. Pthread_mutex_destroy (&foo_mutex);
    10. }

Of course the initialization

[CPP]View Plaincopy
    1. 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
    1. pthread_mutex_t Foo_mutex = Pthread_mutex_initializer;
    2. void Foo ()
    3. {
    4. Pthread_mutex_lock (&foo_mutex);
    5. /* do work . * /
    6. Pthread_mutex_unlock (&foo_mutex);
    7. }


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
  1. #include <pthread.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. pthread_mutex_t mutex = Pthread_mutex_initializer;
  5. pthread_cond_t cond = Pthread_cond_initializer;
  6. void *thread1 (void *);
  7. void *thread2 (void *);
  8. int i=1;
  9. int main (void)
  10. {
  11. pthread_t t_a;
  12. pthread_t T_b;
  13. Pthread_create (&t_a,null,thread2, (void *) NULL); /*create thread t_a*/
  14. Pthread_create (&t_b,null,thread1, (void *) NULL); /*create thread t_b*/
  15. Pthread_join (T_b, NULL); /*wait for exit of t_b*/
  16. Pthread_join (T_a, NULL);
  17. Pthread_mutex_destroy (&mutex);
  18. Pthread_cond_destroy (&cond);
  19. Exit (0);
  20. }
  21. void *thread1 (void *junk)
  22. {
  23. For (i=1;i<=9;i++)
  24. {
  25. Pthread_mutex_lock (&mutex);
  26. if (i%3==0)
  27. Pthread_cond_signal (&cond);
  28. Else
  29. printf ("Thread1 running, i =%d\n", i);
  30. Pthread_mutex_unlock (&mutex);
  31. Sleep (1);
  32. }
  33. }
  34. void *thread2 (void *junk)
  35. {
  36. While (i<9)
  37. {
  38. Pthread_mutex_lock (&mutex);
  39. if (i%3!=0)
  40. Pthread_cond_wait (&cond,&mutex); /*.. */  
  41. printf ("thread2 running, i =%d\n", i);
  42. Pthread_mutex_unlock (&mutex);
  43. Sleep (1);
  44. }
  45. }


Output:

[CPP]View Plaincopy
    1. Thread1 running, i = 1
    2. Thread1 running, i = 2
    3. Thread2 running, i = 3
    4. Thread1 running, i = 4
    5. Thread1 running, i = 5
    6. Thread2 running, i = 6
    7. Thread1 running, i = 7
    8. Thread1 running, i = 8
    9. 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
  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #define MAX 5
  4. pthread_mutex_t mutex = Pthread_mutex_initializer; / * Initialize the mutex * /
  5. pthread_cond_t cond = Pthread_cond_initializer; / * Initialize condition variable * /
  6. typedef struct{
  7. Char Buffer[max];
  8. int how_many;
  9. }buffer;
  10. BUFFER share={"", 0};
  11. Char ch=' A '; /* Initialize ch*/
  12. void *producer (void *);
  13. void *consumer (void *);
  14. int main (void)
  15. {
  16. pthread_t T_read;
  17. pthread_t T_write;
  18. Pthread_create (&t_write,null,producer, (void *) NULL); / * Create process t_a*/
  19. Pthread_create (&t_read,null,consumer, (void *) NULL); / * Create process t_b*/
  20. Pthread_join (T_write, (void * *) NULL);
  21. Pthread_join (T_read, NULL);
  22. Exit (0);
  23. }
  24. void *producer (void *junk)
  25. {
  26. int n=0;
  27. printf ("producer:starting\n");
  28. While (ch!=' K ')
  29. {
  30. Pthread_mutex_lock (&mutex); / * Lock the mutex * /
  31. if (Share.how_many!=max)
  32. {
  33. share.buffer[share.how_many++]=ch++; / * Write letters to cache * /
  34. printf ("Producer:put char[%c]\n", ch-1); /* Print Write Letter * /
  35. if (Share.how_many==max)
  36. {
  37. printf ("producer:signaling full\n");
  38. Pthread_cond_signal (&cond); / * Send a signal if the letter in the cache reaches the maximum value * /
  39. }
  40. }
  41. Pthread_mutex_unlock (&mutex); / * Unlock Mutex * /
  42. }
  43. Sleep (1);
  44. printf ("producer:exiting\n");
  45. return NULL;
  46. }
  47. void *consumer (void *junk)
  48. {
  49. int i;
  50. int n=0;
  51. printf ("consumer:starting\n");
  52. While (ch!=' K ')
  53. {
  54. Pthread_mutex_lock (&mutex); / * Lock the mutex * /
  55. printf ("\nconsumer:waiting\n");
  56. while (Share.how_many!=max)/* If the buffer letter is not equal to the maximum value, wait * /
  57. Pthread_cond_wait (&cond,&mutex);
  58. printf ("consumer:getting buffer::");
  59. For (i=0;share.buffer[i]&&share.how_many;++i,share.how_many--)
  60. Putchar (Share.buffer[i]); / * Loop Output Buffer Letter * /
  61. Putchar (' \ n ');
  62. Pthread_mutex_unlock (&mutex); / * Unlock Mutex * /
  63. }
  64. printf ("consumer:exiting\n");
  65. return NULL;
  66. }

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

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.