-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathdining-philosophers-1.c
105 lines (83 loc) · 2.56 KB
/
dining-philosophers-1.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// This example code is from: https://rosettacode.org/wiki/Dining_philosophers#C
// Please let me know if this does not constitute fair use.
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdarg.h>
// When building, you must link with the external pthread library: for example, 'gcc dining-philosophers-1.c -lpthread'
/* This solution avoids deadlocks by making each person have a different order when they pick up forks.
As long as there is one person who waits for the left fork first and one person who waits for the right fork first,
cycles cannot form.
*/
#define N 5
const char *names[N] = { "Aristotle", "Kant", "Spinoza", "Marx", "Russell" };
pthread_mutex_t forks[N];
#define M 5 /* think bubbles */
const char *topic[M] = { "Spaghetti!", "Life", "Universe", "Everything", "Bathroom" };
#define lock pthread_mutex_lock
#define unlock pthread_mutex_unlock
#define xy(x, y) printf("\033[%d;%dH", x, y)
#define clear_eol(x) print(x, 12, "\033[K")
void print(int y, int x, const char *fmt, ...)
{
static pthread_mutex_t screen = PTHREAD_MUTEX_INITIALIZER;
va_list ap;
va_start(ap, fmt);
lock(&screen);
xy(y + 1, x), vprintf(fmt, ap);
xy(N + 1, 1), fflush(stdout);
unlock(&screen);
}
void eat(int id)
{
int f[2], ration, i; /* forks */
f[0] = f[1] = id;
/* make some (but not all) philosophers lefties.
could have been f[!id] = (id + 1) %N; for example */
f[id & 1] = (id + 1) % N;
clear_eol(id);
print(id, 12, "..oO (forks, need forks)");
for (i = 0; i < 2; i++) {
lock(forks + f[i]);
if (!i) clear_eol(id);
print(id, 12 + (f[i] != id) * 6, "fork%d", f[i]);
/* delay 1 sec to clearly show the order of fork acquisition */
sleep(1);
}
for (i = 0, ration = 3 + rand() % 8; i < ration; i++)
print(id, 24 + i * 4, "nom"), sleep(1);
/* done nomming, give up forks (order doesn't matter) */
for (i = 0; i < 2; i++) unlock(forks + f[i]);
}
void think(int id)
{
int i, t;
char buf[64] = {0};
do {
clear_eol(id);
sprintf(buf, "..oO (%s)", topic[t = rand() % M]);
for (i = 0; buf[i]; i++) {
print(id, i+12, "%c", buf[i]);
if (i < 5) usleep(200000);
}
usleep(500000 + rand() % 1000000);
} while (t);
}
void* philosophize(void *a)
{
int id = *(int*)a;
print(id, 1, "%10s", names[id]);
while(1) think(id), eat(id);
}
int main()
{
int i, id[N];
pthread_t tid[N];
for (i = 0; i < N; i++)
pthread_mutex_init(forks + (id[i] = i), 0);
for (i = 0; i < N; i++)
pthread_create(tid + i, 0, philosophize, id + i);
/* wait forever: the threads don't actually stop */
return pthread_join(tid[0], 0);
}