Skip to content

Commit 389875d

Browse files
committed
Change the implementation of mutex to test and set
1. Directly show the scenarios using Test and Set and its atomic operations. - Use `atomic_flag_test_and_set()` and `atomic_flag_clear()` to implement the original mutex lock and unlock mechanism. - Replace the original condition variable wait mechanism with `atomic_flag_test_and_set()` combined with a `while` loop. 2. Avoid deadlock in `tpool_future_get()`. - The main thread must first wait for the worker to complete the "BBP formula" job. - Subsequently, it should wait for the worker to unlock. - These two operations must occur in this order to avoid deadlock. Swapping them will lead to deadlock.
1 parent 267f1ad commit 389875d

File tree

2 files changed

+14
-20
lines changed

2 files changed

+14
-20
lines changed

examples/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
all:
2-
$(CC) -Wall -o rmw_example rmw_example.c -lpthread -lm
2+
$(CC) -Wall -o rmw_example rmw_example.c -pthread -lm
33
clean:
44
rm -f rmw_example
55
check: all

examples/rmw_example.c

Lines changed: 13 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -16,8 +16,7 @@
1616
struct tpool_future {
1717
atomic_int flag;
1818
void *result;
19-
mtx_t mutex;
20-
cnd_t cond_finished;
19+
atomic_flag lock;
2120
};
2221

2322
typedef struct job {
@@ -51,32 +50,29 @@ static struct tpool_future *tpool_future_create(void)
5150
if (future) {
5251
future->flag = __FUTURE_START;
5352
future->result = NULL;
54-
mtx_init(&future->mutex, mtx_plain);
55-
cnd_init(&future->cond_finished);
53+
atomic_flag_clear(&future->lock);
5654
}
5755
return future;
5856
}
5957

6058
void tpool_future_get(struct tpool_future *future)
6159
{
62-
mtx_lock(&future->mutex);
63-
while ((future->flag & __FUTURE_FINISHED) == 0) {
64-
cnd_wait(&future->cond_finished, &future->mutex);
65-
}
66-
mtx_unlock(&future->mutex);
60+
while (future->flag != __FUTURE_FINISHED)
61+
;
62+
while (atomic_flag_test_and_set(&future->lock))
63+
;
64+
atomic_flag_clear(&future->lock);
6765
}
6866

6967
int tpool_future_destroy(struct tpool_future *future)
7068
{
7169
if (future) {
72-
mtx_lock(&future->mutex);
70+
while (atomic_flag_test_and_set(&future->lock))
71+
;
7372
if (future->flag & __FUTURE_FINISHED) {
74-
mtx_unlock(&future->mutex);
75-
mtx_destroy(&future->mutex);
76-
cnd_destroy(&future->cond_finished);
7773
free(future);
7874
} else {
79-
mtx_unlock(&future->mutex);
75+
atomic_flag_clear(&future->lock);
8076
}
8177
}
8278
return 0;
@@ -102,13 +98,12 @@ static int worker(void *args)
10298
} else {
10399
void *ret_value = job->func(job->args);
104100

105-
mtx_lock(&job->future->mutex);
106-
101+
while (atomic_flag_test_and_set(&job->future->lock))
102+
;
107103
job->future->flag |= __FUTURE_FINISHED;
108104
job->future->result = ret_value;
109-
cnd_broadcast(&job->future->cond_finished);
110105

111-
mtx_unlock(&job->future->mutex);
106+
atomic_flag_clear(&job->future->lock);
112107
free(job->args);
113108
free(job);
114109
}
@@ -248,7 +243,6 @@ int main()
248243
*id = i;
249244
add_job(&thrd_pool, bbp, id);
250245
}
251-
252246
for (int i = 0; i <= PRECISION; i++) {
253247
tpool_future_get(futures[i]);
254248
bbp_sum += *(double *)(futures[i]->result);

0 commit comments

Comments
 (0)