Back to index

glibc  2.9
ex2.c
Go to the documentation of this file.
00001 /* The classic producer-consumer example.
00002    Illustrates mutexes and conditions.
00003    All integers between 0 and 9999 should be printed exactly twice,
00004    once to the right of the arrow and once to the left. */
00005 
00006 #include <stdio.h>
00007 #include "pthread.h"
00008 
00009 #define BUFFER_SIZE 16
00010 
00011 /* Circular buffer of integers. */
00012 
00013 struct prodcons
00014 {
00015   int buffer[BUFFER_SIZE];  /* the actual data */
00016   pthread_mutex_t lock;            /* mutex ensuring exclusive access to buffer */
00017   int readpos, writepos;    /* positions for reading and writing */
00018   pthread_cond_t notempty;  /* signaled when buffer is not empty */
00019   pthread_cond_t notfull;   /* signaled when buffer is not full */
00020 };
00021 
00022 /* Initialize a buffer */
00023 static void
00024 init (struct prodcons *b)
00025 {
00026   pthread_mutex_init (&b->lock, NULL);
00027   pthread_cond_init (&b->notempty, NULL);
00028   pthread_cond_init (&b->notfull, NULL);
00029   b->readpos = 0;
00030   b->writepos = 0;
00031 }
00032 
00033 /* Store an integer in the buffer */
00034 static void
00035 put (struct prodcons *b, int data)
00036 {
00037   pthread_mutex_lock (&b->lock);
00038   /* Wait until buffer is not full */
00039   while ((b->writepos + 1) % BUFFER_SIZE == b->readpos)
00040     {
00041       pthread_cond_wait (&b->notfull, &b->lock);
00042       /* pthread_cond_wait reacquired b->lock before returning */
00043     }
00044   /* Write the data and advance write pointer */
00045   b->buffer[b->writepos] = data;
00046   b->writepos++;
00047   if (b->writepos >= BUFFER_SIZE)
00048     b->writepos = 0;
00049   /* Signal that the buffer is now not empty */
00050   pthread_cond_signal (&b->notempty);
00051   pthread_mutex_unlock (&b->lock);
00052 }
00053 
00054 /* Read and remove an integer from the buffer */
00055 static int
00056 get (struct prodcons *b)
00057 {
00058   int data;
00059   pthread_mutex_lock (&b->lock);
00060   /* Wait until buffer is not empty */
00061   while (b->writepos == b->readpos)
00062     {
00063       pthread_cond_wait (&b->notempty, &b->lock);
00064     }
00065   /* Read the data and advance read pointer */
00066   data = b->buffer[b->readpos];
00067   b->readpos++;
00068   if (b->readpos >= BUFFER_SIZE)
00069     b->readpos = 0;
00070   /* Signal that the buffer is now not full */
00071   pthread_cond_signal (&b->notfull);
00072   pthread_mutex_unlock (&b->lock);
00073   return data;
00074 }
00075 
00076 /* A test program: one thread inserts integers from 1 to 10000,
00077    the other reads them and prints them. */
00078 
00079 #define OVER (-1)
00080 
00081 struct prodcons buffer;
00082 
00083 static void *
00084 producer (void *data)
00085 {
00086   int n;
00087   for (n = 0; n < 10000; n++)
00088     {
00089       printf ("%d --->\n", n);
00090       put (&buffer, n);
00091     }
00092   put (&buffer, OVER);
00093   return NULL;
00094 }
00095 
00096 static void *
00097 consumer (void *data)
00098 {
00099   int d;
00100   while (1)
00101     {
00102       d = get (&buffer);
00103       if (d == OVER)
00104        break;
00105       printf ("---> %d\n", d);
00106     }
00107   return NULL;
00108 }
00109 
00110 int
00111 main (void)
00112 {
00113   pthread_t th_a, th_b;
00114   void *retval;
00115 
00116   init (&buffer);
00117   /* Create the threads */
00118   pthread_create (&th_a, NULL, producer, 0);
00119   pthread_create (&th_b, NULL, consumer, 0);
00120   /* Wait until producer and consumer finish. */
00121   pthread_join (th_a, &retval);
00122   pthread_join (th_b, &retval);
00123   return 0;
00124 }