Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: converted the examples from int->sized_t. i would also settle for any other unsigned integer type

...

Code Block
bgColor#FFcccc
langc
#include <stdio.h>
#include <threads.h>

enum { NTHREADS = 5 };

mtx_t mutex;
cnd_t cond;

int run_step(void *t) {
  static int current_step = 0;
  int my_step = (int)t;

  if (thrd_success != mtx_lock(&mutex)) {
    /* Handle error condition */
  }

  printf("Thread %d has the lock\n", my_step);

  while (current_step != my_step) {
    printf("Thread %d is sleeping...\n", my_step);

    if (thrd_success != cnd_wait(&cond, &mutex)) {
      /* Handle error condition */
    }

    printf("Thread %d woke up\n", my_step);
  }

  /* Do processing ... */
  printf("Thread %d is processing...\n", my_step);
  current_step++;

  /* Signal a waiting task */
  if (thrd_success != cnd_signal(&cond)) {
    /* Handle error condition */
  }

  printf("Thread %d is exiting...\n", my_step);

  if (thrd_success != mtx_unlock(&mutex)) {
    /* Handle error condition */
  }
  return 0;
}

int main(int argc, char** argv) {
  int i;
  thrd_t threads[NTHREADS];
  int step[NTHREADS];

  if (thrd_success != mtx_init(&mutex, mtx_plain)) {
    /* Handle error condition */
  }

 
  if (thrd_success != cnd_init(&cond)) {
    /* Handle error condition */
  }

  /* Create threads */
  for (size_t i = 0; i < NTHREADS; ++i) {
    step[i] = i;
    if (thrd_success != thrd_create(&threads[i], run_step,
                                    (void *)step[i])) {
      /* Handle error condition */
    }
  }

  /* Wait for all threads to complete */
  for (size_t i = NTHREADS - 1; i >!= 0; --i) {
    if (thrd_success != thrd_join(threads[i-1], NULL)) {
      /* Handle error condition */
    }
  }

  mtx_destroy(&mutex);
  cnd_destroy(&cond);
  return 0;
}

...

Time

Thread #
(my_step)

current_step

Action

0

3

0

Thread 3 executes first time: predicate is FALSE -> wait()

1

2

0

Thread 2 executes first time: predicate is FALSE -> wait()

2

4

0

Thread 4 executes first time: predicate is FALSE -> wait()

3

0

0

Thread 0 executes first time: predicate is TRUE -> current_step++; cnd_signal()

4

1

1

Thread 1 executes first time: predicate is TRUE -> current_step++; cnd_signal()

5

3

2

Thread 3 wakes up (scheduler choice): predicate is FALSE -> wait()

6

Deadlock situation! No more threads to run, and a conditional variable signal is needed to wake up the others

...

Code Block
bgColor#ccccff
langc
#include <stdio.h>
#include <threads.h>
 
int run_step(void *t) {
  static int current_step = 0;
  int my_step = (int)t;

  if (thrd_success != mtx_lock(&mutex)) {
    /* Handle error condition */
  }

  printf("Thread %d has the lock\n", my_step);

  while (current_step != my_step) {
    printf("Thread %d is sleeping...\n", my_step);

    if (thrd_success != cnd_wait(&cond, &mutex)) {
      /* Handle error condition */
    }

    printf("Thread %d woke up\n", my_step);
  }

  /* Do processing ... */
  printf("Thread %d is processing...\n", my_step);

  current_step++;

  /* Signal ALL waiting tasks */
  if (thrd_success != cnd_broadcast(&cond)) {
    /* Handle error condition */
  }

  printf("Thread %d is exiting...\n", my_step);

  if (thrd_success != mtx_unlock(&mutex)) {
    /* Handle error condition */
  }
  return 0;
}

The fact that all threads will be awake solves the problem because each one ends up executing Awakening all threads solves guarantess the liveness property because each thread will execute its condition predicate test, and exactly one will succeed and continue execution.

...

Code Block
bgColor#ccccff
langc
#include <Windows.h>
#include <stdio.h>
 
CRITICAL_SECTION lock;
CONDITION_VARIABLE cond;
 
DWORD WINAPI run_step(LPVOID t) {
  static intsize_t current_step = 0;
  intsize_t my_step = (intsize_t)t;

  EnterCriticalSection(&lock);  
  printf("Thread %d has the lock\n", my_step);

  while (current_step != my_step) {
    printf("Thread %d is sleeping...\n", my_step);
 
    if (!SleepConditionVariableCS(&cond, &lock, INFINITE)) {
      /* Handle error condition */
    }

    printf("Thread %d woke up\n", my_step);
  }

  /* Do processing ... */
  printf("Thread %d is processing...\n", my_step);

  current_step++;
 
  LeaveCriticalSection(&lock);
 
  /* Signal ALL waiting tasks */
  WakeAllConditionVariable(&cond);
 
  printf("Thread %d is exiting...\n", my_step);
  return 0;
}
 
enum { NTHREADS = 5 };

 
int main(int argc, char ** argvargv[]) {
  HANDLE threads[NTHREADS];
  
  InitializeCriticalSection(&lock);
  InitializeConditionVariable(&cond);
 
  /* Create threads */
  for (intsize_t i = 0; i < NTHREADS; ++i) {
    threads[i] = CreateThread(NULL, 0, run_step, (LPVOID)i, 0, NULL);
  }
 
  /* Wait for all threads to complete */
  WaitForMultipleObjects(NTHREADS, threads, TRUE, INFINITE);
 
  DeleteCriticalSection(&lock);
 
  return 0;
}

...