aboutsummaryrefslogtreecommitdiff
path: root/linuxthreads/Examples
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1998-03-11 12:42:25 +0000
committerUlrich Drepper <drepper@redhat.com>1998-03-11 12:42:25 +0000
commit5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3 (patch)
treec9c82db2ff92537b921361a02a284b0e18a594b8 /linuxthreads/Examples
parent3d76e7784700c20fc222920b2a22baba006daa15 (diff)
downloadglibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.zip
glibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.tar.gz
glibc-5afdca0087dad2994ad4fcdfe7f489f4dbcab7b3.tar.bz2
LinuxThreads library.
1998-03-11 00:42 Wolfram Gloger <wmglo@dent.med.uni-muenchen.de> * linuxthreads/manager.c: Enable resetting of the thread scheduling policy to SCHED_OTHER when the parent thread has a different one. 1998-02-01 13:51 Ulrich Drepper <drepper@cygnus.com> * sysdeps/unix/sysv/linux/bits/posix_opt.h: Define _POSIX_ASYNCHRONOUS_IO. * sysdeps/pthread/pthread.h: Define bits for Unix98 variants of mutexes. * mutex.c: Implement new mutex types. * internals.h: Include <signal.h>. * libpthread.map: Add __erno_location and __h_errno_location. * errno.c: Return pointer to variable actually in use. This might not be the one in the thread structure. * internals.h (struct _pthread_descr_struct): Add new fields p_errnop and p_h_errnop. * manager.c (__pthread_manager): Set p_errnop and p_h_errnop member of manager thread structure. (pthread_handle_create): Set p_errnop and p_h_errnop members for new thread. * pthread.c: Adapt initializer for thread structures. (__pthread_initial_thread): Set p_errnop and p_h_errnop member. (__pthread_reset_main_thread): Reset p_errnop and p_h_errnop of current thread to global variables. 1998-01-31 17:27 Ulrich Drepper <drepper@cygnus.com> * rwlock.c: New file. * Makefile (libpthread-routines): Add rwlock. * sysdeps/pthread/pthread.h: Define data structures and declare functions. * libpthread.map: Add new functions. 1997-12-18 13:50 Philip Blundell <pb@nexus.co.uk> * sysdeps/arm/pt-machine.h: New file; add ARM support. * sysdeps/arm/Implies: likewise. * README: Document it. 1997-12-13 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * signals.c: Remove unneeded initializer for sigwaited, saving a 1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * semaphore.c (sem_init): Set sem_spinlock only if available. 1997-12-04 01:48 Ulrich Drepper <drepper@cygnus.com> * mutex.c: Implement PTHREAD_MUTEX_CHECKERROR. * sysdeps/pthread/pthread.h: Define PTHREAD_MUTEX_CHECKERROR. * Makefile: Update from LinuxThreads 0.7. * internals.h. Likewise. * manager.c: Likewise. * mutex.c: Likewise. * pthread.c: Likewise. * signals.c: Likewise. * specific.c: Likewise. * Examples/ex3.c: Likewise. 1997-11-20 18:13 Ulrich Drepper <drepper@cygnus.com> * pthread.c (__pthread_reset_main_thread): Close pipe only if still open. 1997-10-29 05:38 Ulrich Drepper <drepper@cygnus.com> * wrapsyscall.c: Add socket functions which are also cancelation points. 1997-10-19 21:40 Wolfram Gloger <wg@wolfram.dent.med.uni-muenchen.de> * specific.c (__libc_internal_tsd_set, __libc_internal_tsd_get): New functions for fast thread specific data within libc. * internals.h: Add new array p_libc_specific to struct _pthread_descr_struct. * sysdeps/pthread/bits/libc-lock.h: Declare new functions. 1997-10-13 05:39 Ulrich Drepper <drepper@cygnus.com> * semaphore.h: Add __BEGIN_DECLS/__END_DECLS. Reported by Ralf Corsepius <corsepiu@faw.uni-ulm.de>. 1997-08-29 03:05 Ulrich Drepper <drepper@cygnus.com> * internals.h (struct _pthread_descr_struct): Add definitions for two-level specific key handling. * manager.c (pthread_handle_create): Initialize specific memory array. * specific.c: Implement two-level key handling. * weaks.c: Don't provide dummy key handling. * sysdeps/pthread/bits/libc-lock.h: Typedef __libc_lock_t (no #define). Add definition of __libc_key_t. * sysdeps/unix/sysv/linux/bits/local_lim.h: Define PTHREAD_KEYS_MAX as 1024. Add definition of _POSIX_THREAD_DESTRUCTOR_ITERATIONS and PTHREAD_DESTRUCTOR_ITERATIONS. * manager.c (pthread_handle_create): Compare mmap result with MAP_FAILED. * ptfork.c: Rename to __pthread_atfork and make old name a weak alias. * sysdeps/pthread/bits/pthread.h: Add prototype for __pthread_atfork. 1997-08-22 19:04 Richard Henderson <rth@cygnus.com> sysdeps/sparc -> sysdeps/sparc/sparc32 sysdeps/sparc64 -> sysdeps/sparc/sparc64 * internals.h: Change definition of THREAD_SELF to be an expression, not a statement that did a return. * sysdeps/alpha/pt-machine.h (THREAD_SELF): Update accordingly. * sysdeps/sparc/sparc32/pt-machine.h (THREAD_SELF, INIT_THREAD_SELF): Follow Solaris and use a "system reserved" register (%g6) to hold the thread descriptor. * sysdeps/sparc/sparc64/pt-machine.h: Likewise. 1997-08-03 00:09 Ulrich Drepper <drepper@cygnus.com> * mutex.c: Correct pthread_once. Patch by Xavier Leroy. * sysdeps/pthread/pthread.h: Add prototype for __pthread_once. * sysdeps/pthread/bits/pthread.h: Add macros for __libc_once. * semaphore.c: Include spinlock.h only when needed. * specific.c (__pthread_setsepcific, __pthread_getspecific): Reject keys for entries not in use. * weaks.c: Implement key handling functions for real. 1997-06-29 01:04 Richard Henderson <richard@gnu.ai.mit.edu> Initial sparc64-linux support: * linuxthreads/sysdeps/sparc64/Implies: New file. * linuxthreads/sysdeps/sparc64/pt-machine.h: Likewise. 1997-06-29 00:48 Ulrich Drepper <drepper@cygnus.com> * semaphore.c: Include spinlock.h at correct place. Patch by HJ Lu. 1997-06-13 10:06 Richard Henderson <rth@tamu.edu> The Great Bit File Move: * sysdeps/alpha/semaphorebits.h: -> .../bits/semaphore.h. * sysdeps/powerpc/semaphorebits.h: Likewise. * sysdeps/pthread/cmpxchg/semaphorebits.h: Likewise. * sysdeps/pthread/no-cmpxchg/semaphorebits.h: Likewise. * sysdeps/pthread/libc-lock.h: -> bits/ * sysdeps/pthread/stdio-lock.h: Likewise. * sysdeps/unix/sysv/linux/local_lim.h: Likewise. * sysdeps/unix/sysv/linux/posix_opt.h: Likewise. * semaphore.h: Likewise. * sysdeps/pthread/pthread.h: Likewise. * lockfile.c: <foo.h> -> <bits/foo.h>. * semaphore.h: Likewise. * Makefile: (headers): foo.h -> bits/foo.h. * sysdeps/pthread/Makefile: Likewise. 1997-04-11 01:18 Andreas Schwab <schwab@issan.informatik.uni-dortmund.de> * semaphore.c (sem_init): Set sem_spinlock only if available. * sysdeps/m68k/pt-machine.h (testandset, __compare_and_swap): Fix asm constraints. 1997-04-09 03:00 Ulrich Drepper <drepper@cygnus.com> Update from LinuxThreads 0.6. * attr.c (pthread_attr_getdetachstate): Use __sched_get_priority_max and __sched_get_priority_min instead of names without `__'. * manager.c: Rewrite large parts to implement opaque pthread_t. * cancel.c: Adapt for opaque pthread_t type. * condvar.c: Likewise. * errno.c: Likewise. * join.c: Likewise. * mutex.c: Likewise. * pthread.c: Likewise. * signals.c: Likewise. * specific.c: Likewise. * restart.h: Likewise. * queue.h: Likewise. * Examples/ex3.c: Likewise. * Examples/ex4.c: Likewise. * sysdeps/pthread/pthread.h: Likewise. * pthread.c: Accumulate time for all threads in thread manager. * semaphore.c: Implement fallback implementation for architectures sometimes missing compare-exchange operations. * cancel.c (pthread_cancel): Validate handle argument. * join.c (pthread_join): Likewise. (pthread_detach): Likewise. * signals.c (pthread_kill): Likewise. * spinlock.h (acquire): Use __sched_yield not sched_yield. * queue.h (enqueue): Enqueue thread according to priority. * internals.c (struct pthread_start_args): New struct for passing args to cloning function. (struct _pthread): Rename to _pthread_descr_struct and adapt for opaque pthread_t. * Examples/Makefile (clean): Pass -f option to rm. * sysdeps/i386/pt-machine.h: Add check for compare-exchange instruction and define TEST_FOR_COMPARE_AND_SWAP. * sysdeps/i386/i486/pt-machine.h: Removed. * sysdeps/unix/sysv/linux/local_lim.h (PTHREAD_THREADS_MAX): Increase to 1024. 1997-04-04 16:38 Ulrich Drepper <drepper@cygnus.com> * restart.h (suspend): Clear p_signal before suspending. (suspend_with_cancellation): Likewise. Patch by Xavier Leroy <Xavier.Leroy@inria.fr>. * weaks.c: Make __pthread_key_create return 1. * sysdeps/pthread/libc-lock.h: Define __libc_key_create, __libc_getspecific, __libc_setspecific, and __libc_key_t. * sysdeps/pthread/stdio-lock.h: Don't care for implementation not using libio. 1997-03-19 15:13 Miguel de Icaza <miguel@nuclecu.unam.mx> * sysdeps/sparc/pt-machine (RELEASE): Fix. 1997-03-01 07:55 Geoff Keating <geoffk@ozemail.com.au> * sysdeps/powerpc/Implies: Added. * sysdeps/powerpc/pt-machine.h: Added. * sysdeps/powerpc/semaphorebits.h: Added. 1997-01-22 01:22 Ulrich Drepper <drepper@cygnus.com> * linuxtheads/pthread.c (__pthread_initial_thread): Correct initializer. (__pthread_manager_thread): Likewise. Reported by Andreas Jaeger. 1997-01-18 22:15 Richard Henderson <rth@tamu.edu> Since sigset_t no longer fits in a register, we can't pass in the thread's initial mask so easily. Take this opportunity to simplify the clone implementation by only accepting a single void* argument. * linuxthreads/manager.c (__pthread_manager): Put thread vitals in the thread struct instead of as arguments through clone. (pthread_start_thread): Look for them there. * linuxthreads/internals.h (struct _pthread): Add p_initial_fn, p_initial_fn_arg, p_initial_mask. Fix __pthread_manager proto. * linuxthreads/pthread.c (pthread_initialize_manager): Revise clone invocation.
Diffstat (limited to 'linuxthreads/Examples')
-rw-r--r--linuxthreads/Examples/Makefile15
-rw-r--r--linuxthreads/Examples/ex1.c36
-rw-r--r--linuxthreads/Examples/ex2.c116
-rw-r--r--linuxthreads/Examples/ex3.c144
-rw-r--r--linuxthreads/Examples/ex4.c107
-rw-r--r--linuxthreads/Examples/ex5.c102
6 files changed, 520 insertions, 0 deletions
diff --git a/linuxthreads/Examples/Makefile b/linuxthreads/Examples/Makefile
new file mode 100644
index 0000000..c68b367
--- /dev/null
+++ b/linuxthreads/Examples/Makefile
@@ -0,0 +1,15 @@
+CC=gcc
+CFLAGS=-g -O -Wall -I.. -D_REENTRANT
+LIBPTHREAD=../libpthread.a
+
+PROGS=ex1 ex2 ex3 ex4 ex5 proxy
+
+all: $(PROGS)
+
+.c:
+ $(CC) $(CFLAGS) -o $* $*.c $(LIBPTHREAD)
+
+$(PROGS):
+
+clean:
+ rm -f $(PROGS)
diff --git a/linuxthreads/Examples/ex1.c b/linuxthreads/Examples/ex1.c
new file mode 100644
index 0000000..c399fab
--- /dev/null
+++ b/linuxthreads/Examples/ex1.c
@@ -0,0 +1,36 @@
+/* Creates two threads, one printing 10000 "a"s, the other printing
+ 10000 "b"s.
+ Illustrates: thread creation, thread joining. */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "pthread.h"
+
+void * process(void * arg)
+{
+ int i;
+ fprintf(stderr, "Starting process %s\n", (char *) arg);
+ for (i = 0; i < 10000; i++) {
+ write(1, (char *) arg, 1);
+ }
+ return NULL;
+}
+
+int main()
+{
+ int retcode;
+ pthread_t th_a, th_b;
+ void * retval;
+
+ retcode = pthread_create(&th_a, NULL, process, "a");
+ if (retcode != 0) fprintf(stderr, "create a failed %d\n", retcode);
+ retcode = pthread_create(&th_b, NULL, process, "b");
+ if (retcode != 0) fprintf(stderr, "create b failed %d\n", retcode);
+ retcode = pthread_join(th_a, &retval);
+ if (retcode != 0) fprintf(stderr, "join a failed %d\n", retcode);
+ retcode = pthread_join(th_b, &retval);
+ if (retcode != 0) fprintf(stderr, "join b failed %d\n", retcode);
+ return 0;
+}
+
diff --git a/linuxthreads/Examples/ex2.c b/linuxthreads/Examples/ex2.c
new file mode 100644
index 0000000..3f7f115
--- /dev/null
+++ b/linuxthreads/Examples/ex2.c
@@ -0,0 +1,116 @@
+/* The classic producer-consumer example.
+ Illustrates mutexes and conditions.
+ All integers between 0 and 9999 should be printed exactly twice,
+ once to the right of the arrow and once to the left. */
+
+#include <stdio.h>
+#include "pthread.h"
+
+#define BUFFER_SIZE 16
+
+/* Circular buffer of integers. */
+
+struct prodcons {
+ int buffer[BUFFER_SIZE]; /* the actual data */
+ pthread_mutex_t lock; /* mutex ensuring exclusive access to buffer */
+ int readpos, writepos; /* positions for reading and writing */
+ pthread_cond_t notempty; /* signaled when buffer is not empty */
+ pthread_cond_t notfull; /* signaled when buffer is not full */
+};
+
+/* Initialize a buffer */
+
+void init(struct prodcons * b)
+{
+ pthread_mutex_init(&b->lock, NULL);
+ pthread_cond_init(&b->notempty, NULL);
+ pthread_cond_init(&b->notfull, NULL);
+ b->readpos = 0;
+ b->writepos = 0;
+}
+
+/* Store an integer in the buffer */
+
+void put(struct prodcons * b, int data)
+{
+ pthread_mutex_lock(&b->lock);
+ /* Wait until buffer is not full */
+ while ((b->writepos + 1) % BUFFER_SIZE == b->readpos) {
+ pthread_cond_wait(&b->notfull, &b->lock);
+ /* pthread_cond_wait reacquired b->lock before returning */
+ }
+ /* Write the data and advance write pointer */
+ b->buffer[b->writepos] = data;
+ b->writepos++;
+ if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
+ /* Signal that the buffer is now not empty */
+ pthread_cond_signal(&b->notempty);
+ pthread_mutex_unlock(&b->lock);
+}
+
+/* Read and remove an integer from the buffer */
+
+int get(struct prodcons * b)
+{
+ int data;
+ pthread_mutex_lock(&b->lock);
+ /* Wait until buffer is not empty */
+ while (b->writepos == b->readpos) {
+ pthread_cond_wait(&b->notempty, &b->lock);
+ }
+ /* Read the data and advance read pointer */
+ data = b->buffer[b->readpos];
+ b->readpos++;
+ if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
+ /* Signal that the buffer is now not full */
+ pthread_cond_signal(&b->notfull);
+ pthread_mutex_unlock(&b->lock);
+ return data;
+}
+
+/* A test program: one thread inserts integers from 1 to 10000,
+ the other reads them and prints them. */
+
+#define OVER (-1)
+
+struct prodcons buffer;
+
+void * producer(void * data)
+{
+ int n;
+ for (n = 0; n < 10000; n++) {
+ printf("%d --->\n", n);
+ put(&buffer, n);
+ }
+ put(&buffer, OVER);
+ return NULL;
+}
+
+void * consumer(void * data)
+{
+ int d;
+ while (1) {
+ d = get(&buffer);
+ if (d == OVER) break;
+ printf("---> %d\n", d);
+ }
+ return NULL;
+}
+
+int main()
+{
+ pthread_t th_a, th_b;
+ void * retval;
+
+ init(&buffer);
+ /* Create the threads */
+ pthread_create(&th_a, NULL, producer, 0);
+ pthread_create(&th_b, NULL, consumer, 0);
+ /* Wait until producer and consumer finish. */
+ pthread_join(th_a, &retval);
+ pthread_join(th_b, &retval);
+ return 0;
+}
+
+
+
diff --git a/linuxthreads/Examples/ex3.c b/linuxthreads/Examples/ex3.c
new file mode 100644
index 0000000..002bc90
--- /dev/null
+++ b/linuxthreads/Examples/ex3.c
@@ -0,0 +1,144 @@
+/* Multi-thread searching.
+ Illustrates: thread cancellation, cleanup handlers. */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <pthread.h>
+
+/* Defines the number of searching threads */
+#define NUM_THREADS 5
+
+/* Function prototypes */
+void *search(void *);
+void print_it(void *);
+
+/* Global variables */
+pthread_t threads[NUM_THREADS];
+pthread_mutex_t lock;
+int tries;
+
+int main(argc, argv)
+ int argc;
+ char ** argv;
+{
+ int i;
+ int pid;
+
+ /* create a number to search for */
+ pid = getpid();
+ printf("Searching for the number = %d...\n", pid);
+
+ /* Initialize the mutex lock */
+ pthread_mutex_init(&lock, NULL);
+
+ /* Create the searching threads */
+ for (i=0; i<NUM_THREADS; i++)
+ pthread_create(&threads[i], NULL, search, (void *)pid);
+
+ /* Wait for (join) all the searching threads */
+ for (i=0; i<NUM_THREADS; i++)
+ pthread_join(threads[i], NULL);
+
+ printf("It took %d tries to find the number.\n", tries);
+
+ /* Exit the program */
+ return 0;
+}
+
+/* This is the cleanup function that is called
+ when the threads are cancelled */
+
+void print_it(void *arg)
+{
+ int *try = (int *) arg;
+ pthread_t tid;
+
+ /* Get the calling thread's ID */
+ tid = pthread_self();
+
+ /* Print where the thread was in its search when it was cancelled */
+ printf("Thread %lx was canceled on its %d try.\n", tid, *try);
+}
+
+/* This is the search routine that is executed in each thread */
+
+void *search(void *arg)
+{
+ int num = (int) arg;
+ int i, j, ntries;
+ pthread_t tid;
+
+ /* get the calling thread ID */
+ tid = pthread_self();
+
+ /* use the thread ID to set the seed for the random number generator */
+ /* Since srand and rand are not thread-safe, serialize with lock */
+ pthread_mutex_lock(&lock);
+ srand((int)tid);
+ i = rand() & 0xFFFFFF;
+ pthread_mutex_unlock(&lock);
+ ntries = 0;
+
+ /* Set the cancellation parameters --
+ - Enable thread cancellation
+ - Defer the action of the cancellation */
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_setcanceltype(PTHREAD_CANCEL_DEFERRED, NULL);
+
+ /* Push the cleanup routine (print_it) onto the thread
+ cleanup stack. This routine will be called when the
+ thread is cancelled. Also note that the pthread_cleanup_push
+ call must have a matching pthread_cleanup_pop call. The
+ push and pop calls MUST be at the same lexical level
+ within the code */
+
+ /* Pass address of `ntries' since the current value of `ntries' is not
+ the one we want to use in the cleanup function */
+
+ pthread_cleanup_push(print_it, (void *)&ntries);
+
+ /* Loop forever */
+ while (1) {
+ i = (i + 1) & 0xFFFFFF;
+ ntries++;
+
+ /* Does the random number match the target number? */
+ if (num == i) {
+ /* Try to lock the mutex lock --
+ if locked, check to see if the thread has been cancelled
+ if not locked then continue */
+ while (pthread_mutex_trylock(&lock) == EBUSY)
+ pthread_testcancel();
+
+ /* Set the global variable for the number of tries */
+ tries = ntries;
+ printf("Thread %lx found the number!\n", tid);
+
+ /* Cancel all the other threads */
+ for (j=0; j<NUM_THREADS; j++)
+ if (threads[j] != tid) pthread_cancel(threads[j]);
+
+ /* Break out of the while loop */
+ break;
+ }
+
+ /* Every 100 tries check to see if the thread has been cancelled. */
+ if (ntries % 100 == 0) {
+ pthread_testcancel();
+ }
+ }
+
+ /* The only way we can get here is when the thread breaks out
+ of the while loop. In this case the thread that makes it here
+ has found the number we are looking for and does not need to run
+ the thread cleanup function. This is why the pthread_cleanup_pop
+ function is called with a 0 argument; this will pop the cleanup
+ function off the stack without executing it */
+
+ pthread_cleanup_pop(0);
+ return((void *)0);
+}
+
diff --git a/linuxthreads/Examples/ex4.c b/linuxthreads/Examples/ex4.c
new file mode 100644
index 0000000..83bc54c
--- /dev/null
+++ b/linuxthreads/Examples/ex4.c
@@ -0,0 +1,107 @@
+/* Making a library function that uses static variables thread-safe.
+ Illustrates: thread-specific data, pthread_once(). */
+
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+
+/* This is a typical example of a library function that uses
+ static variables to accumulate results between calls.
+ Here, it just returns the concatenation of all string arguments
+ that were given to it. */
+
+#if 0
+
+char * str_accumulate(char * s)
+{
+ static char accu[1024] = { 0 };
+ strcat(accu, s);
+ return accu;
+}
+
+#endif
+
+/* Of course, this cannot be used in a multi-threaded program
+ because all threads store "accu" at the same location.
+ So, we'll use thread-specific data to have a different "accu"
+ for each thread. */
+
+/* Key identifying the thread-specific data */
+static pthread_key_t str_key;
+/* "Once" variable ensuring that the key for str_alloc will be allocated
+ exactly once. */
+static pthread_once_t str_alloc_key_once = PTHREAD_ONCE_INIT;
+
+/* Forward functions */
+static void str_alloc_key(void);
+static void str_alloc_destroy_accu(void * accu);
+
+/* Thread-safe version of str_accumulate */
+
+char * str_accumulate(char * s)
+{
+ char * accu;
+
+ /* Make sure the key is allocated */
+ pthread_once(&str_alloc_key_once, str_alloc_key);
+ /* Get the thread-specific data associated with the key */
+ accu = (char *) pthread_getspecific(str_key);
+ /* It's initially NULL, meaning that we must allocate the buffer first. */
+ if (accu == NULL) {
+ accu = malloc(1024);
+ if (accu == NULL) return NULL;
+ accu[0] = 0;
+ /* Store the buffer pointer in the thread-specific data. */
+ pthread_setspecific(str_key, (void *) accu);
+ printf("Thread %lx: allocating buffer at %p\n", pthread_self(), accu);
+ }
+ /* Now we can use accu just as in the non thread-safe code. */
+ strcat(accu, s);
+ return accu;
+}
+
+/* Function to allocate the key for str_alloc thread-specific data. */
+
+static void str_alloc_key(void)
+{
+ pthread_key_create(&str_key, str_alloc_destroy_accu);
+ printf("Thread %lx: allocated key %d\n", pthread_self(), str_key);
+}
+
+/* Function to free the buffer when the thread exits. */
+/* Called only when the thread-specific data is not NULL. */
+
+static void str_alloc_destroy_accu(void * accu)
+{
+ printf("Thread %lx: freeing buffer at %p\n", pthread_self(), accu);
+ free(accu);
+}
+
+/* Test program */
+
+void * process(void * arg)
+{
+ char * res;
+ res = str_accumulate("Result of ");
+ res = str_accumulate((char *) arg);
+ res = str_accumulate(" thread");
+ printf("Thread %lx: \"%s\"\n", pthread_self(), res);
+ return NULL;
+}
+
+int main(int argc, char ** argv)
+{
+ char * res;
+ pthread_t th1, th2;
+
+ res = str_accumulate("Result of ");
+ pthread_create(&th1, NULL, process, "first");
+ pthread_create(&th2, NULL, process, "second");
+ res = str_accumulate("initial thread");
+ printf("Thread %lx: \"%s\"\n", pthread_self(), res);
+ pthread_join(th1, NULL);
+ pthread_join(th2, NULL);
+ pthread_exit(NULL);
+}
diff --git a/linuxthreads/Examples/ex5.c b/linuxthreads/Examples/ex5.c
new file mode 100644
index 0000000..366668e
--- /dev/null
+++ b/linuxthreads/Examples/ex5.c
@@ -0,0 +1,102 @@
+/* The classic producer-consumer example, implemented with semaphores.
+ All integers between 0 and 9999 should be printed exactly twice,
+ once to the right of the arrow and once to the left. */
+
+#include <stdio.h>
+#include "pthread.h"
+#include "semaphore.h"
+
+#define BUFFER_SIZE 16
+
+/* Circular buffer of integers. */
+
+struct prodcons {
+ int buffer[BUFFER_SIZE]; /* the actual data */
+ int readpos, writepos; /* positions for reading and writing */
+ sem_t sem_read; /* number of elements available for reading */
+ sem_t sem_write; /* number of locations available for writing */
+};
+
+/* Initialize a buffer */
+
+void init(struct prodcons * b)
+{
+ sem_init(&b->sem_write, 0, BUFFER_SIZE - 1);
+ sem_init(&b->sem_read, 0, 0);
+ b->readpos = 0;
+ b->writepos = 0;
+}
+
+/* Store an integer in the buffer */
+
+void put(struct prodcons * b, int data)
+{
+ /* Wait until buffer is not full */
+ sem_wait(&b->sem_write);
+ /* Write the data and advance write pointer */
+ b->buffer[b->writepos] = data;
+ b->writepos++;
+ if (b->writepos >= BUFFER_SIZE) b->writepos = 0;
+ /* Signal that the buffer contains one more element for reading */
+ sem_post(&b->sem_read);
+}
+
+/* Read and remove an integer from the buffer */
+
+int get(struct prodcons * b)
+{
+ int data;
+ /* Wait until buffer is not empty */
+ sem_wait(&b->sem_read);
+ /* Read the data and advance read pointer */
+ data = b->buffer[b->readpos];
+ b->readpos++;
+ if (b->readpos >= BUFFER_SIZE) b->readpos = 0;
+ /* Signal that the buffer has now one more location for writing */
+ sem_post(&b->sem_write);
+ return data;
+}
+
+/* A test program: one thread inserts integers from 1 to 10000,
+ the other reads them and prints them. */
+
+#define OVER (-1)
+
+struct prodcons buffer;
+
+void * producer(void * data)
+{
+ int n;
+ for (n = 0; n < 10000; n++) {
+ printf("%d --->\n", n);
+ put(&buffer, n);
+ }
+ put(&buffer, OVER);
+ return NULL;
+}
+
+void * consumer(void * data)
+{
+ int d;
+ while (1) {
+ d = get(&buffer);
+ if (d == OVER) break;
+ printf("---> %d\n", d);
+ }
+ return NULL;
+}
+
+int main()
+{
+ pthread_t th_a, th_b;
+ void * retval;
+
+ init(&buffer);
+ /* Create the threads */
+ pthread_create(&th_a, NULL, producer, 0);
+ pthread_create(&th_b, NULL, consumer, 0);
+ /* Wait until producer and consumer finish. */
+ pthread_join(th_a, &retval);
+ pthread_join(th_b, &retval);
+ return 0;
+}