-
Notifications
You must be signed in to change notification settings - Fork 0
/
sense.c
88 lines (78 loc) · 2.56 KB
/
sense.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
#include <stddef.h>
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <sys/time.h>
#include <pthread.h>
/* Synchronization primitive - Sense-reversed asymmetric barrier w/ closure */
/*
* |barrier| and await/bwait/bgo/bclose implement a Sense-reversed barrier
* with a couple of twists - bwait() waits for all await()s, but does not
* release await() - bgo() does that. This allows one thread to bwait() for
* all workers to arrive at the barrier, do some work to aggregate and
* prepare for a next phase, and then release the workers.
*
* This barrier also supports |bclose|, which causes new await()s to return
* immediately with an error. This allows closing down a problem cleanly.
*
* See The Art of Multiprocessor Programming (Herlihy & Shavit), first ed.,
* section 17.3 for discussion of a sense-reversing barrier.
*
* The split between await() and bwait() and support for closure is non
* standard and I have not seen it in literature, but it is pretty useful.
*/
struct barrier {
int max;
int val;
bool sense;
bool closed;
pthread_mutex_t mu;
pthread_cond_t cv;
};
bool await(struct barrier *bp, bool *sense) {
pthread_mutex_lock(&bp->mu);
if (bp->closed) {
pthread_mutex_unlock(&bp->mu);
return true;
}
int val = bp->val--;
if (val == 1)
pthread_cond_broadcast(&bp->cv);
while (bp->sense != *sense) {
pthread_cond_wait(&bp->cv, &bp->mu);
if (bp->closed) {
pthread_mutex_unlock(&bp->mu);
return false;
}
}
*sense = !(*sense);
pthread_mutex_unlock(&bp->mu);
return false;
}
void binit(struct barrier *bp, int max) {
bp->max = max;
bp->val = max;
bp->sense = true;
bp->closed = false;
}
void bwait(struct barrier *bp) {
pthread_mutex_lock(&bp->mu);
while (bp->val != 0)
pthread_cond_wait(&bp->cv, &bp->mu);
pthread_mutex_unlock(&bp->mu);
}
void bgo(struct barrier *bp, bool *sense) {
pthread_mutex_lock(&bp->mu);
bp->val = bp->max;
bp->sense = *sense;
*sense = !(*sense);
pthread_cond_broadcast(&bp->cv);
pthread_mutex_unlock(&bp->mu);
}
void bclose(struct barrier *bp) {
pthread_mutex_lock(&bp->mu);
bp->closed = true;
pthread_cond_broadcast(&bp->cv);
pthread_mutex_unlock(&bp->mu);
}
/* -------------------- CUT ON THE DOTTED LINE *************/