/* file: init_weak.c author: Ted Baker version: $Revision$ last modified: by $Author$ on $Date$ purpose: Demonstrate an unreliable way of trying to avoid reinitialization of global data by each thread, as motivation for 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 such 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_good.c for a better 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; int init_flag = 0; /* is initialized to 0 at process start time */ pthread_mutex_t M; void initialize (int id) { int i; if (! init_flag) { /* window for race between threads is here if two threads fetch the value 0 before one increments init_count, both will execute the initialization code, and if that happens there may be a problem */ init_flag = 1; PCHECK (pthread_mutex_init (&M, NULL)); /* 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; 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); }