Versions Compared

Key

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

...

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;
}

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

...

For example, the following sequence of events can occur:

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

...

Code Block
bgColor#ccccff
langc

struct multi_threaded_flags {
  volatile unsigned int flag1 : 2;
  volatile 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;
  pthread_mutexmtx_t mutex;
};

struct mtf_mutex flags;

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

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

...