Versions Compared

Key

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

...

Deadlock can happen when multiple threads each holds a lock the other needs and are waiting for each other to release the resource. One way to fix the problem is to avoid circular wait by locking the mutex in a predefined order.

CON12-J. Avoid deadlock by requesting and releasing locks in the same+order describes the deadlock solution for Java

Noncompliant Code Example

Based on runtime environment and the scheduler on the operating system, the following code will have different behaviors. Let's assume function thread1 and thread2 are called consecutively as in pthread_create is called from thread2 right after pthread_create in called for thread1. If lucky, the code will run without any problems. In other times, the code will deadlock in which thread1 try to lock m1 while thread2 try to lock on m2 and the program will not progress.

Code Block
bgColor#ffcccc
#include <pthread.h>

void *thread1(void *ptr);
void *thread2(void *ptr);

pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;

void *thread1(void *ptr) {

  pthread_mutex_lock(&m1);
  /* do some stuff that require locking mutex1 */

  pthread_mutex_lock(&m2);
  /* do some stuff that require locking mutex2 */

  pthread_mutex_unlock(&m2);
  pthread_mutex_unlock(&m1);

  return NULL;
}

void *thread2(void *ptr) {

  pthread_mutex_lock(&m2);
  /* do some stuff that require locking mutex2 */

  pthread_mutex_lock(&m1);
  /* do some stuff that require locking mutex1 */

  pthread_mutex_unlock(&m1);
  pthread_mutex_unlock(&m2);

  return NULL;
}

Compliant Solution

The solution to the deadlock problem is to lock in predefined order. In the following example, each thread will lock m1 first then m2. This way circular wait problem is avoided and one thread requires a lock will guarantee it will require the next lock.

Code Block
bgColor#ccccff
#include <pthread.h>

void *thread1(void *ptr);
void *thread2(void *ptr);

pthread_mutex_t m1 = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_t m2 = PTHREAD_MUTEX_INITIALIZER;

void *thread1(void *ptr) {

  pthread_mutex_lock(&m1);
  pthread_mutex_lock(&m2);

  /* do some stuff that require locking mutex1 */
  /* do some stuff that require locking mutex2 */

  pthread_mutex_unlock(&m2);
  pthread_mutex_unlock(&m1);

  return NULL;
}

void *thread2(void *ptr) {

  pthread_mutex_lock(&m1);
  pthread_mutex_lock(&m2);
  /* do some stuff that require locking mutex1 */
  /* do some stuff that require locking mutex2 */

  pthread_mutex_unlock(&m1);
  pthread_mutex_unlock(&m2);

  return NULL;
}