1 /*
2  * Copyright (c) 2006-2021, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  */
9 /* The classic producer-consumer example.
10    Illustrates mutexes and conditions.
11    All integers between 0 and 9999 should be printed exactly twice,
12    once to the right of the arrow and once to the left. */
13 
14 #include <stdio.h>
15 #include "pthread.h"
16 
17 #define BUFFER_SIZE 16
18 
19 /* Circular buffer of integers. */
20 
21 struct prodcons {
22   int buffer[BUFFER_SIZE];      /* the actual data */
23   pthread_mutex_t lock;         /* mutex ensuring exclusive access to buffer */
24   int readpos, writepos;        /* positions for reading and writing */
25   pthread_cond_t notempty;      /* signaled when buffer is not empty */
26   pthread_cond_t notfull;       /* signaled when buffer is not full */
27 };
28 
29 /* Initialize a buffer */
30 
init(struct prodcons * b)31 static void init(struct prodcons * b)
32 {
33   pthread_mutex_init(&b->lock, NULL);
34   pthread_cond_init(&b->notempty, NULL);
35   pthread_cond_init(&b->notfull, NULL);
36   b->readpos = 0;
37   b->writepos = 0;
38 }
39 
40 /* Store an integer in the buffer */
put(struct prodcons * b,int data)41 static void put(struct prodcons * b, int data)
42 {
43   pthread_mutex_lock(&b->lock);
44   /* Wait until buffer is not full */
45   while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) {
46     pthread_cond_wait(&b->notfull, &b->lock);
47     /* pthread_cond_wait reacquired b->lock before returning */
48   }
49   /* Write the data and advance write pointer */
50   b->buffer[b->writepos] = data;
51   b->writepos++;
52   if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
53   /* Signal that the buffer is now not empty */
54   pthread_cond_signal(&b->notempty);
55   pthread_mutex_unlock(&b->lock);
56 }
57 
58 /* Read and remove an integer from the buffer */
59 
get(struct prodcons * b)60 static int get(struct prodcons * b)
61 {
62   int data;
63   pthread_mutex_lock(&b->lock);
64   /* Wait until buffer is not empty */
65   while (b->writepos == b->readpos) {
66     pthread_cond_wait(&b->notempty, &b->lock);
67   }
68   /* Read the data and advance read pointer */
69   data = b->buffer[b->readpos];
70   b->readpos++;
71   if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
72   /* Signal that the buffer is now not full */
73   pthread_cond_signal(&b->notfull);
74   pthread_mutex_unlock(&b->lock);
75   return data;
76 }
77 
78 /* A test program: one thread inserts integers from 1 to 10000,
79    the other reads them and prints them. */
80 
81 #define OVER (-1)
82 
83 struct prodcons buffer;
84 
producer(void * data)85 static void * producer(void * data)
86 {
87   int n;
88   for (n = 0; n < 10000; n++) {
89     printf("%d --->\n", n);
90     put(&buffer, n);
91   }
92   put(&buffer, OVER);
93   return NULL;
94 }
95 
consumer(void * data)96 static void * consumer(void * data)
97 {
98   int d;
99   while (1) {
100     d = get(&buffer);
101     if (d == OVER) break;
102     printf("---> %d\n", d);
103   }
104   return NULL;
105 }
106 
libc_ex2(void)107 int libc_ex2(void)
108 {
109   pthread_t th_a, th_b;
110   void * retval;
111 
112   init(&buffer);
113   /* Create the threads */
114   pthread_create(&th_a, NULL, producer, 0);
115   pthread_create(&th_b, NULL, consumer, 0);
116   /* Wait until producer and consumer finish. */
117   pthread_join(th_a, &retval);
118   pthread_join(th_b, &retval);
119   return 0;
120 }
121 #include <finsh.h>
122 FINSH_FUNCTION_EXPORT(libc_ex2, example 2 for libc);
123