...
| 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" |
...