Logo AND Algorithmique Numérique Distribuée

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