歡迎來到Linux教程網
Linux教程網
Linux教程網
Linux教程網
Linux教程網 >> Linux編程 >> Linux編程 >> 使用POSIX線程解決“生產者/消費者”問題

使用POSIX線程解決“生產者/消費者”問題

日期:2017/3/1 11:17:57   编辑:Linux編程

使用POSIX線程解決“生產者/消費者”問題:

  1. /*
  2. * File : pc.cpp
  3. *
  4. * Title : Demo Producer/Consumer.
  5. *
  6. * Short : A solution to the producer consumer problem using pthreads.
  7. * This is a simple FIFO pipe between two tasks. The primary problem is
  8. * ensuring that the producer blocks if the FIFO is full, and the consumer
  9. * blocks if it is empty, and avoiding data-races along the way. A secondary
  10. * concern is that there is as little interference between the two tasks as
  11. * possible.
  12. *
  13. * Author : Andrae Muys
  14. *
  15. * Date : 18 September 1997
  16. */
  17. #include <stdlib.h>
  18. #include <pthread.h>
  19. #include <assert.h>
  20. #ifdef _WIN32
  21. # include <windows.h>
  22. # define SLEEP(ms) Sleep(ms)
  23. #elif defined(LINUX)
  24. # include <unistd.h>
  25. # define SLEEP(ms) sleep(ms)
  26. #endif
  27. #define QUEUE_SIZE 10
  28. #define LOOP 20
  29. void* producer (void *args);
  30. void* consumer (void *args);
  31. typedef struct
  32. {
  33. int buf[QUEUE_SIZE];
  34. long head, tail;
  35. bool full, empty;
  36. pthread_mutex_t *mutex;
  37. pthread_cond_t *notFull, *notEmpty;
  38. } Queue;
  39. Queue* queueInit (void);
  40. void queueDelete (Queue *q);
  41. void queueAdd (Queue *q, int in);
  42. void queueDel (Queue *q, int *out);
  43. int main(int argc, char* argv[])
  44. {
  45. Queue* fifo = queueInit ();
  46. assert(fifo != NULL);
  47. pthread_t pro, con;
  48. pthread_create (&pro, NULL, &producer, fifo);
  49. pthread_create (&con, NULL, &consumer, fifo);
  50. pthread_join (pro, NULL);
  51. pthread_join (con, NULL);
  52. queueDelete (fifo);
  53. return 0;
  54. }
  55. void* producer (void *q)
  56. {
  57. Queue* fifo = (Queue *)q;
  58. for (int i = 0; i < LOOP; i++)
  59. {
  60. // 臨界區操作:若隊列未滿,添加新數據
  61. pthread_mutex_lock (fifo->mutex);
  62. while (fifo->full)
  63. {
  64. printf ("producer: Queue FULL.\n");
  65. pthread_cond_wait (fifo->notFull, fifo->mutex);
  66. }
  67. queueAdd (fifo, i);
  68. pthread_mutex_unlock (fifo->mutex);
  69. // 數據添加結束,發“隊列有數據”信號
  70. pthread_cond_signal (fifo->notEmpty);
  71. SLEEP (100);
  72. }
  73. // 與上面類似
  74. for (int i = 0; i < LOOP; i++)
  75. {
  76. pthread_mutex_lock (fifo->mutex);
  77. while (fifo->full)
  78. {
  79. printf ("producer: Queue FULL.\n");
  80. pthread_cond_wait (fifo->notFull, fifo->mutex);
  81. }
  82. queueAdd (fifo, i);
  83. pthread_mutex_unlock (fifo->mutex);
  84. pthread_cond_signal (fifo->notEmpty);
  85. SLEEP (200);
  86. }
  87. return (NULL);
  88. }
  89. void* consumer (void *q)
  90. {
  91. int d;
  92. Queue *fifo = (Queue *)q;
  93. for (int i = 0; i < LOOP; i++)
  94. {
  95. // 臨界區操作:若隊列不空,則取出數據
  96. pthread_mutex_lock (fifo->mutex);
  97. while (fifo->empty)
  98. {
  99. printf ("consumer: Queue EMPTY.\n");
  100. pthread_cond_wait (fifo->notEmpty, fifo->mutex);
  101. }
  102. queueDel (fifo, &d);
  103. pthread_mutex_unlock (fifo->mutex);
  104. // 取完數據,發“隊列不滿”信號
  105. pthread_cond_signal (fifo->notFull);
  106. printf ("consumer: recieved %d.\n", d);
  107. SLEEP(200);
  108. }
  109. // 與上面類似
  110. for (int i = 0; i < LOOP; i++)
  111. {
  112. pthread_mutex_lock (fifo->mutex);
  113. while (fifo->empty)
  114. {
  115. printf ("consumer: Queue EMPTY.\n");
  116. pthread_cond_wait (fifo->notEmpty, fifo->mutex);
  117. }
  118. queueDel (fifo, &d);
  119. pthread_mutex_unlock (fifo->mutex);
  120. pthread_cond_signal (fifo->notFull);
  121. printf ("consumer: recieved %d.\n", d);
  122. SLEEP (50);
  123. }
  124. return (NULL);
  125. }
  126. Queue *queueInit (void)
  127. {
  128. Queue *q = (Queue *)malloc (sizeof (Queue));
  129. if (q == NULL) return (NULL);
  130. q->empty = true;
  131. q->full = false;
  132. q->head = 0;
  133. q->tail = 0;
  134. q->mutex = (pthread_mutex_t *) malloc (sizeof (pthread_mutex_t));
  135. pthread_mutex_init (q->mutex, NULL);
  136. q->notFull = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
  137. pthread_cond_init (q->notFull, NULL);
  138. q->notEmpty = (pthread_cond_t *) malloc (sizeof (pthread_cond_t));
  139. pthread_cond_init (q->notEmpty, NULL);
  140. return (q);
  141. }
  142. void queueDelete (Queue *q)
  143. {
  144. pthread_mutex_destroy (q->mutex);
  145. free (q->mutex);
  146. pthread_cond_destroy (q->notFull);
  147. free (q->notFull);
  148. pthread_cond_destroy (q->notEmpty);
  149. free (q->notEmpty);
  150. free (q);
  151. }
  152. void queueAdd (Queue *q, int in)
  153. {
  154. q->buf[q->tail] = in;
  155. q->tail++;
  156. if (q->tail == QUEUE_SIZE) // 循環隊列
  157. q->tail = 0;
  158. if (q->tail == q->head) // 添加數據時“觸頂”
  159. q->full = true;
  160. q->empty = false;
  161. return;
  162. }
  163. void queueDel (Queue *q, int *out)
  164. {
  165. *out = q->buf[q->head];
  166. q->head++;
  167. if (q->head == QUEUE_SIZE) // 循環隊列
  168. q->head = 0;
  169. if (q->head == q->tail) // 取出數據時“觸底”
  170. q->empty = true;
  171. q->full = false;
  172. return;
  173. }
Copyright © Linux教程網 All Rights Reserved