...
Code Block |
---|
Thread 1: register 0 = flags Thread 1: register 0 &= ~mask(flag1) Thread 2: register 0 = flags Thread 2: register 0 &= ~mask(flag2) Thread 1: register 0 |= 1 << shift(flag1) Thread 1: flags = register 0 Thread 2: register 0 |= 2 << shift(flag2) Thread 2: flags = register 0 |
Compliant Solution (Bit-field,
...
Mutex)
This compliant solution protects all accesses of the flags with a mutex, thereby preventing any data races. Finally, the flags are embedded in a union alongside a long
, and a static assertion guarantees that the flags do not occupy more space than the long
. This technique prevents any data not checked by the mutex from being accessed or modified with the bit-fields on platforms that do not comply with C11.
Code Block | ||||
---|---|---|---|---|
| ||||
#include <threads.h> #include <assert.h> struct multi_threaded_flags { unsigned int flag1 : 2; unsigned int flag2 : 2; }; static_assert( sizeof(long) >= sizeof(struct multi_threaded_flags), "A long type will not hold the flags on this architecture." ); union mtf_protect { struct multi_threaded_flags s; long padding; }; struct mtf_mutex { union mtf_protect u; mtx_t mutex; }; struct mtf_mutex flags; void chk_flags(void) { static_assert( sizeof(long) >= sizeof(struct multi_threaded_flags), "A long type will not hold the flags on this architecture." ); } int thread1(void *arg) { if (thrd_success != mtx_lock(&flags.mutex)) { /* Handle error */ } flags.u.s.flag1 = 1; if (thrd_success != mtx_unlock(&flags.mutex)) { /* Handle error */ } return 0; } int thread2(void *arg) { if (thrd_success != mtx_lock(&flags.mutex)) { /* Handle error */ } flags.u.s.flag2 = 2; if (thrd_success != mtx_unlock(&flags.mutex)) { /* Handle error */ } return 0; } |
...