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