| /* linux-dp.c --- dining philosophers, on LinuxThreads | |
| Jim Blandy <jimb@cygnus.com> --- March 1999 */ | |
| /* It's okay to edit this file and shift line numbers around. The | |
| tests use gdb_get_line_number to find source locations, so they | |
| don't depend on having certain line numbers in certain places. */ | |
| #include <stdarg.h> | |
| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <pthread.h> | |
| #include <sys/time.h> | |
| #include <sys/types.h> | |
| #include <unistd.h> | |
| /* The number of philosophers at the table. */ | |
| int num_philosophers; | |
| /* Mutex ordering - | |
| If you want to lock a mutex M, all the mutexes you have locked | |
| already must appear before M on this list. | |
| fork_mutex[0] | |
| fork_mutex[1] | |
| ... | |
| fork_mutex[num_philosophers - 1] | |
| stdout_mutex | |
| random_mutex | |
| */ | |
| /* You must hold this mutex while writing to stdout. */ | |
| pthread_mutex_t stdout_mutex; | |
| /* You must hold this mutex while calling any of the random number | |
| generation routines. */ | |
| pthread_mutex_t random_mutex; | |
| /* array of mutexes, one for each fork; fork_mutex[i] is to the left | |
| of philosopher i. A philosopher is holding fork i iff his/her | |
| thread has locked fork_mutex[i]. */ | |
| pthread_mutex_t *fork_mutex; | |
| /* array of threads, one representing each philosopher. */ | |
| pthread_t *philosophers; | |
| void * | |
| xmalloc (size_t n) | |
| { | |
| void *p = malloc (n); | |
| if (! p) | |
| { | |
| fprintf (stderr, "out of memory\n"); | |
| exit (2); | |
| } | |
| return p; | |
| } | |
| void | |
| shared_printf (char *format, ...) | |
| { | |
| va_list ap; | |
| va_start (ap, format); | |
| pthread_mutex_lock (&stdout_mutex); | |
| vprintf (format, ap); | |
| pthread_mutex_unlock (&stdout_mutex); | |
| va_end (ap); | |
| } | |
| int | |
| shared_random () | |
| { | |
| int result; | |
| pthread_mutex_lock (&random_mutex); | |
| result = rand (); | |
| pthread_mutex_unlock (&random_mutex); | |
| return result; | |
| } | |
| void | |
| my_usleep (long usecs) | |
| { | |
| struct timeval timeout; | |
| timeout.tv_sec = usecs / 1000000; | |
| timeout.tv_usec = usecs % 1000000; | |
| select (0, 0, 0, 0, &timeout); | |
| } | |
| void | |
| random_delay () | |
| { | |
| my_usleep ((shared_random () % 2000) * 100); | |
| } | |
| void | |
| print_philosopher (int n, char left, char right) | |
| { | |
| int i; | |
| shared_printf ("%*s%c %d %c\n", (n * 4) + 2, "", left, n, right); | |
| } | |
| void * | |
| philosopher (void *data) | |
| { | |
| int n = * (int *) data; | |
| print_philosopher (n, '_', '_'); | |
| #if 1 | |
| if (n == num_philosophers - 1) | |
| for (;;) | |
| { | |
| /* The last philosopher is different. He goes for his right | |
| fork first, so there is no cycle in the mutex graph. */ | |
| /* Grab the right fork. */ | |
| pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); | |
| print_philosopher (n, '_', '!'); | |
| random_delay (); | |
| /* Then grab the left fork. */ | |
| pthread_mutex_lock (&fork_mutex[n]); | |
| print_philosopher (n, '!', '!'); | |
| random_delay (); | |
| print_philosopher (n, '_', '_'); | |
| pthread_mutex_unlock (&fork_mutex[n]); | |
| pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); | |
| random_delay (); | |
| } | |
| else | |
| #endif | |
| for (;;) | |
| { | |
| /* Grab the left fork. */ | |
| pthread_mutex_lock (&fork_mutex[n]); | |
| print_philosopher (n, '!', '_'); | |
| random_delay (); | |
| /* Then grab the right fork. */ | |
| pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); | |
| print_philosopher (n, '!', '!'); | |
| random_delay (); | |
| print_philosopher (n, '_', '_'); | |
| pthread_mutex_unlock (&fork_mutex[n]); | |
| pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); | |
| random_delay (); | |
| } | |
| return (void *) 0; | |
| } | |
| int | |
| main (int argc, char **argv) | |
| { | |
| num_philosophers = 5; | |
| /* Set up the mutexes. */ | |
| { | |
| pthread_mutexattr_t ma; | |
| int i; | |
| pthread_mutexattr_init (&ma); | |
| pthread_mutex_init (&stdout_mutex, &ma); | |
| pthread_mutex_init (&random_mutex, &ma); | |
| fork_mutex = xmalloc (num_philosophers * sizeof (fork_mutex[0])); | |
| for (i = 0; i < num_philosophers; i++) | |
| pthread_mutex_init (&fork_mutex[i], &ma); | |
| pthread_mutexattr_destroy (&ma); | |
| } | |
| /* Set off the threads. */ | |
| { | |
| int i; | |
| int *numbers = xmalloc (num_philosophers * sizeof (*numbers)); | |
| pthread_attr_t ta; | |
| philosophers = xmalloc (num_philosophers * sizeof (*philosophers)); | |
| pthread_attr_init (&ta); | |
| for (i = 0; i < num_philosophers; i++) | |
| { | |
| numbers[i] = i; | |
| /* linuxthreads.exp: create philosopher */ | |
| pthread_create (&philosophers[i], &ta, philosopher, &numbers[i]); | |
| } | |
| pthread_attr_destroy (&ta); | |
| } | |
| /* linuxthreads.exp: info threads 2 */ | |
| sleep (1000000); | |
| /* Drink yourself into oblivion. */ | |
| for (;;) | |
| sleep (1000000); | |
| return 0; | |
| } |