/* file: init_good.c author: Ted Baker version: $Revision$ last modified: by $Author$ on $Date$ purpose: Demonstrate the right way to avoid reinitialization of global data by each thread, using pthread_once(). The problem we are trying to solve is the initialization problem for *separately compiled* libraries. Such a library consists of a collection of functions, which could be called by any thread. The first call to the library must take responsibility for initializing all the static data of the library. The problem is how to tell which is the first call to a function of the library, and so avoid reinitializing the static data, over and over? We have an easy solution for simple variables, like the int variable count in the code below. The compiler and linker arrange to initialize these at program load time. The problem becomes difficult when we need to initialize more complex structures, such as pointers to dynamically allocated objects, and other information that may not be known until execution time. The example should really use a separately compiled library. We kept it in a single file, to make it easier to read. See init_weak.c for a less reliable solution. */ #define _XOPEN_SOURCE 500 #define _REENTRANT #include #include #include #include #define PCHECK(CALL){int result;\ if ((result = (CALL)) != 0) {\ fprintf (stderr, "FATAL: %s (%s)", strerror(result), #CALL);\ exit (-1);}} #define NTHREADS 10 int count = 0; pthread_mutex_t M; pthread_once_t init_flag = PTHREAD_ONCE_INIT; void init_routine () { PCHECK (pthread_mutex_init (&M, NULL)); } void initialize (int id) { int i; PCHECK (pthread_once (&init_flag, init_routine)); /* executing the above more than once is erroneous */ PCHECK (pthread_mutex_lock (&M)); /* At this point we would normally initialize other global data, under protection of the mutex. Instead, we have some code to try to detect whether mutual exclusion is working. */ count++; fprintf (stderr, "thread %d inside critical section\n", id); if (count > 1) fprintf (stderr, "MUTUAL EXCLUSION FAILED: %d threads in critical section\n", count); for (i = 0; i < 10000000; i++) /* waste time */; if (count > 1) fprintf (stderr, "MUTUAL EXCLUSION FAILED: %d threads in critical section\n", count); count--; PCHECK (pthread_mutex_unlock (&M)); } void * my_thread_body (void *arg) { initialize ((int) arg); return NULL; } int main (int argc, char **argv) { pthread_t thread_id[NTHREADS]; int i; PCHECK (pthread_setconcurrency (2)); for (i = 0; i < NTHREADS; i++) { PCHECK (pthread_create ( &thread_id[i], /* place to store the id of new thread */ NULL, /* use default thread creation attributes */ my_thread_body, /* function for thread to execute */ (void *) i)); /* pass no parameter */ } for (i = 1; i < NTHREADS; i++) { PCHECK (pthread_join (thread_id[i], NULL)); } exit (0); }