Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: thread functions are now void*(void*)

...

Code Block
bgColor#ffcccc
langc
struct multi_threaded_flags {
  unsigned char flag1;
  unsigned char flag2;
};
 
struct multi_threaded_flags flags;
 
void* thread1(void*) {
  flags.flag1 = 1;
  return 0;
}

void* thread2(void*) {
  flags.flag2 = 2;
  return 0;
}

Although this code appears to be harmless, it is possible that flag1 and flag2 are stored in the same word. If both assignments occur on a thread-scheduling interleaving that ends with both stores occurring after one another, it is possible that only one of the flags will be set as intended, and the other flag will equal its previous value, because both chars are represented by the same word, which is the smallest unit the processor can work on. C99 makes no guarantees that these flags can be modified concurrently.

...

Code Block
bgColor#FFcccc
langc
struct multi_threaded_flags {
  unsigned int flag1 : 2;
  unsigned int flag2 : 2;
};

struct multi_threaded_flags flags;

void* thread1(void*) {
  flags.flag1 = 1;
  return 0;
}

void* thread2(void*) {
  flags.flag2 = 2;
  return 0;
}

The C Standard, Section 3.14.3 [ISO/IEC 9899:2011], states:

...

Code Block
bgColor#ccccff
langc
#include <threads.h>
 
struct multi_threaded_flags {
  unsigned int flag1 : 2;
  unsigned int flag2 : 2;
};

union mtf_protect {
  struct multi_threaded_flags s;
  long padding;
};

static_assert(sizeof(long) >=
              sizeof(struct multi_threaded_flags));

struct mtf_mutex {
  union mtf_protect u;
  mtx_t mutex;
};

struct mtf_mutex flags;

void* thread1(void*) {
  int result;
  if ((result = mtx_lock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  flags.u.s.flag1 = 1;
  if ((result = mtx_unlock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  return 0;
}

void* thread2(void*) {
  int result;
  if ((result = mtx_lock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  flags.u.s.flag2 = 2;
  if ((result = mtx_unlock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  return 0;
}

Static assertions are discussed in detail in DCL03-C. Use a static assertion to test the value of a constant expression.

...