diff options
Diffstat (limited to 'linuxthreads/Examples/ex4.c')
-rw-r--r-- | linuxthreads/Examples/ex4.c | 115 |
1 files changed, 115 insertions, 0 deletions
diff --git a/linuxthreads/Examples/ex4.c b/linuxthreads/Examples/ex4.c new file mode 100644 index 0000000000..5c8b929e22 --- /dev/null +++ b/linuxthreads/Examples/ex4.c @@ -0,0 +1,115 @@ +/* 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 */ + +static char * +str_accumulate (const 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 */ + +static 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, (void *) "first"); + pthread_create (&th2, NULL, process, (void *) "second"); + res = str_accumulate ("initial thread"); + printf ("Thread %lx: \"%s\"\n", pthread_self (), res); + pthread_join (th1, NULL); + pthread_join (th2, NULL); + return 0; +} |