...
Code Block | ||||
---|---|---|---|---|
| ||||
struct multi_threaded_flags { unsigned char flag1; unsigned char flag2; }; struct multi_threaded_flags flags; void * thread1(void * arg) { flags.flag1 = 1; return 0; } void * thread2(void * arg) { flags.flag2 = 2; return 0; } |
...
The same code is compliant when run on a C11-compliant platform. Unlike C99, C11 explicitly defines a memory location and provides the following note, in section clause 3.14.2 [ISO/IEC 9899:2011]:
...
Adjacent bit-fields may be stored in a single memory location. Consequently, modifying adjacent bit-fields in different threads is undefined behavior, even in C11:
Code Block | ||||
---|---|---|---|---|
| ||||
struct multi_threaded_flags { unsigned int flag1 : 2; unsigned int flag2 : 2; }; struct multi_threaded_flags flags; void * thread1(void * arg) { flags.flag1 = 1; return 0; } void* thread2(void * arg) { flags.flag2 = 2; return 0; } |
...
Code Block | ||||
---|---|---|---|---|
| ||||
#include <threads.h> #include <assert.h> struct multi_threaded_flags { unsigned int flag1 : 2; unsigned int flag2 : 2; }; 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)); struct mtf_mutex { union mtf_protect u; mtx_t mutex; }; struct mtf_mutex flags; void* void *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; } void * 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; } |
...
Bibliography
[ISO/IEC 9899:2011] | Section Clause 3.14, "Memory Location" |
...