/* file: init_bad.c author: Ted Baker version: $Revision$ last modified: by $Author$ on $Date$ purpose: Motivate need to avoid reinitialization of global data by each thread, by showing that we cannot allow a mutex to be reinitialized once thread have started using it. 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 variables count and init_flag 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_weak.c for an unreliable solution, and init_good.c for a good 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; void initialize (int id) { int i; 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; 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); }