Logo AND Algorithmique Numérique Distribuée

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