Logo AND Algorithmique Numérique Distribuée

Public GIT Repository
Change the prototype of xbt_thread_create(), sorry.
[simgrid.git] / examples / gras / synchro / philosopher.c
1 /* $Id$ */
2
3 /* philosopher - classical dinning philosopher as a demo xbt syncro stuff   */
4
5 /* Copyright (c) 2007 Martin Quinson. All rights reserved.                  */
6
7 /* This program is free software; you can redistribute it and/or modify it
8  * under the terms of the license (GNU LGPL) which comes with this package. */
9
10 #include "gras.h"
11 #include "xbt/synchro.h"
12
13 XBT_LOG_NEW_DEFAULT_CATEGORY(philo, "Logs of this example");
14
15
16 /** Philosopher logic **/
17 int lunch_amount = 10;
18 int philosopher_amount;
19
20 xbt_mutex_t mutex;
21 xbt_cond_t *forks;
22
23 #define THINKING 0
24 #define EATING 1
25 int *state;
26
27 int *id;                        /* to pass a pointer to the threads without race condition */
28
29 static void pickup(int id, int lunch)
30 {
31   INFO2("Thread %d gets hungry (lunch #%d)", id, lunch);
32   xbt_mutex_acquire(mutex);
33   while (state[(id + (philosopher_amount - 1)) % philosopher_amount] == EATING
34          || state[(id + 1) % philosopher_amount] == EATING) {
35     xbt_cond_wait(forks[id], mutex);
36   }
37
38   state[id] = EATING;
39   xbt_assert1(state[(id + (philosopher_amount - 1)) % philosopher_amount] ==
40               THINKING
41               && state[(id + 1) % philosopher_amount] == THINKING,
42               "Philosopher %d eats at the same time that one of its neighbors!!!",
43               id);
44
45   xbt_mutex_release(mutex);
46   INFO1("Thread %d eats", id);
47 }
48
49 static void putdown(int id)
50 {
51   INFO1("Thread %d is full", id);
52   xbt_mutex_acquire(mutex);
53   state[id] = THINKING;
54   xbt_cond_signal(forks
55                   [(id + (philosopher_amount - 1)) % philosopher_amount]);
56   xbt_cond_signal(forks[(id + 1) % philosopher_amount]);
57
58   xbt_mutex_release(mutex);
59   INFO1("Thread %d thinks", id);
60 }
61
62 /*
63  * Some additionnal code to let the father wait the childs
64  */
65 xbt_mutex_t mut_end;
66 xbt_cond_t cond_end;
67 int running_threads;
68
69 xbt_mutex_t dead_end;
70
71 /* Code ran by each thread */
72 static void philo_thread(void *arg)
73 {
74   int id = *(int *) arg;
75   int i;
76
77   for (i = 0; i < lunch_amount; i++) {
78     pickup(id, i);
79     gras_os_sleep(id / 100.0);  /* each philosopher sleeps and eat a time related to its ID */
80     putdown(id);
81     gras_os_sleep(id / 100.0);
82   }
83
84   xbt_mutex_acquire(mut_end);
85   running_threads--;
86   xbt_cond_signal(cond_end);
87   xbt_mutex_release(mut_end);
88
89   /* Enter an endless loop to test the killing facilities */
90   INFO1
91     ("Thread %d tries to enter the dead-end; hopefully, the master will cancel it",
92      id);
93   xbt_mutex_acquire(dead_end);
94   INFO1("Oops, thread %d reached the dead-end. Cancelation failed", id);
95 }
96
97 int philosopher(int argc, char *argv[]);
98 int philosopher(int argc, char *argv[])
99 {
100   int i;
101   xbt_thread_t *philosophers;
102
103   gras_init(&argc, argv);
104   xbt_assert0(argc >= 2,
105               "This program expects one argument (the amount of philosophers)");
106
107   /* initializations of the philosopher mecanisms */
108   philosopher_amount = atoi(argv[1]);
109   state = xbt_new0(int, philosopher_amount);
110   id = xbt_new0(int, philosopher_amount);
111   forks = xbt_new(xbt_cond_t, philosopher_amount);
112   philosophers = xbt_new(xbt_thread_t, philosopher_amount);
113
114   mutex = xbt_mutex_init();
115   for (i = 0; i < philosopher_amount; i++) {
116     state[i] = THINKING;
117     id[i] = i;
118     forks[i] = xbt_cond_init();
119   }
120
121   /* setup the ending mecanism */
122   running_threads = philosopher_amount;
123   cond_end = xbt_cond_init();
124   mut_end = xbt_mutex_init();
125   dead_end = xbt_mutex_init();
126   xbt_mutex_acquire(dead_end);
127
128   INFO2("Spawn the %d threads (%d lunches scheduled)", philosopher_amount,
129         lunch_amount);
130   /* spawn threads */
131   for (i = 0; i < philosopher_amount; i++) {
132     char *name = bprintf("thread %d", i);
133     philosophers[i] = xbt_thread_create(name, philo_thread, &id[i],0/*not joinable*/);
134     free(name);
135   }
136
137   /* wait for them */
138   xbt_mutex_acquire(mut_end);
139   while (running_threads)
140     xbt_cond_wait(cond_end, mut_end);
141   xbt_mutex_release(mut_end);
142
143   INFO0("Cancel all childs");
144   /* nuke them threads */
145   for (i = 0; i < philosopher_amount; i++) {
146     xbt_thread_cancel(philosophers[i]);
147   }
148
149   xbt_mutex_release(dead_end);
150   gras_exit();
151   return 0;
152 }