1 | #include <pthread.h> |
2 | #include <stdbool.h> |
3 | #include <stdio.h> |
4 | #include <stdlib.h> |
5 | #include <string.h> |
6 | #include <unistd.h> |
7 | #include <atomic.h> |
8 | |
9 | static pthread_cond_t cond1 = PTHREAD_COND_INITIALIZER; |
10 | static pthread_mutex_t mut1 = PTHREAD_MUTEX_INITIALIZER; |
11 | |
12 | static pthread_cond_t cond2 = PTHREAD_COND_INITIALIZER; |
13 | static pthread_mutex_t mut2 = PTHREAD_MUTEX_INITIALIZER; |
14 | |
15 | static bool last_round; |
16 | static int ntogo; |
17 | static bool alldone; |
18 | |
19 | |
20 | static void * |
21 | cons (void *arg) |
22 | { |
23 | pthread_mutex_lock (mutex: &mut1); |
24 | |
25 | do |
26 | { |
27 | if (atomic_decrement_and_test (&ntogo)) |
28 | { |
29 | pthread_mutex_lock (mutex: &mut2); |
30 | alldone = true; |
31 | pthread_cond_signal (cond: &cond2); |
32 | pthread_mutex_unlock (mutex: &mut2); |
33 | } |
34 | |
35 | pthread_cond_wait (cond: &cond1, mutex: &mut1); |
36 | } |
37 | while (! last_round); |
38 | |
39 | pthread_mutex_unlock (mutex: &mut1); |
40 | |
41 | return NULL; |
42 | } |
43 | |
44 | |
45 | int |
46 | main (int argc, char *argv[]) |
47 | { |
48 | int opt; |
49 | int err; |
50 | int nthreads = 10; |
51 | int nrounds = 100; |
52 | bool keeplock = false; |
53 | |
54 | while ((opt = getopt (argc: argc, argv: argv, shortopts: "n:r:k" )) != -1) |
55 | switch (opt) |
56 | { |
57 | case 'n': |
58 | nthreads = atol (nptr: optarg); |
59 | break; |
60 | case 'r': |
61 | nrounds = atol (nptr: optarg); |
62 | break; |
63 | case 'k': |
64 | keeplock = true; |
65 | break; |
66 | } |
67 | |
68 | ntogo = nthreads; |
69 | |
70 | pthread_t th[nthreads]; |
71 | int i; |
72 | for (i = 0; __builtin_expect (i < nthreads, 1); ++i) |
73 | if (__glibc_unlikely ((err = pthread_create (&th[i], NULL, cons, (void *) (long) i)) != 0)) |
74 | printf (format: "pthread_create: %s\n" , strerror (errnum: err)); |
75 | |
76 | for (i = 0; __builtin_expect (i < nrounds, 1); ++i) |
77 | { |
78 | pthread_mutex_lock (mutex: &mut2); |
79 | while (! alldone) |
80 | pthread_cond_wait (cond: &cond2, mutex: &mut2); |
81 | pthread_mutex_unlock (mutex: &mut2); |
82 | |
83 | pthread_mutex_lock (mutex: &mut1); |
84 | if (! keeplock) |
85 | pthread_mutex_unlock (mutex: &mut1); |
86 | |
87 | ntogo = nthreads; |
88 | alldone = false; |
89 | if (i + 1 >= nrounds) |
90 | last_round = true; |
91 | |
92 | pthread_cond_broadcast (cond: &cond1); |
93 | |
94 | if (keeplock) |
95 | pthread_mutex_unlock (mutex: &mut1); |
96 | } |
97 | |
98 | for (i = 0; i < nthreads; ++i) |
99 | if ((err = pthread_join (th: th[i], NULL)) != 0) |
100 | printf (format: "pthread_create: %s\n" , strerror (errnum: err)); |
101 | |
102 | return 0; |
103 | } |
104 | |