Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Code Block
bgColor#ffcccc
langc
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;
}

...

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* arg) {
  flags.flag1 = 1;
  return 0;
}

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

...

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, C11, 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
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* arg) {
  int result;
  if ((resultthrd_success != mtx_lock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  flags.u.s.flag1 = 1;
  if ((resultthrd_success != mtx_unlock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  return 0;
}
 
void* thread2(void* arg) {
  int result;
  if ((resultthrd_success != mtx_lock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  flags.u.s.flag2 = 2;
  if ((resultthrd_success != mtx_unlock(&flags.mutex)) == thrd_error) {
    /* Handle error */
  }
  return 0;
}

...