c recursive mutex

Keywords: C Red Hat

Before we talk about recursive mutexes, let's talk about what mutexes are. There are four types in the third edition of apue:

  • PTHREAD_MUTEX_NORMAL: Standard type with no special error or deadlock detection.

    Deadlock occurs when a mutex is unlocked in the same thread.

  • PTHREAD_MUTEX_RECURSIVE: Recursive type.

    This mutex type allows the same thread to lock the mutex multiple times before it is unlocked.Recursive mutex maintains the count of locks that will not be released if the number of unlocks and the number of locks are different, and no other thread can lock this mutex.

  • PTHREAD_MUTEX_ERRORCHECK: Provides error detection.If a mutex is locked in the same thread that has not been unlocked, an error will be reported.However, when tested on centos7 (3.10.0-957.el7.x86_64), gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39), it was found that an unlocked mutex was unlocked on the same thread and no errors were reported.

  • PTHREAD_MUTEX_DEFAULT

In pthread.h of the gcc (GCC) 4.8.5 20150623 (Red Hat 4.8.5-39) environment, the mutex type is defined as follows:

/* Mutex types.  */
enum
{
  PTHREAD_MUTEX_TIMED_NP,
  PTHREAD_MUTEX_RECURSIVE_NP,
  PTHREAD_MUTEX_ERRORCHECK_NP,
  PTHREAD_MUTEX_ADAPTIVE_NP
#if defined __USE_UNIX98 || defined __USE_XOPEN2K8
  ,
  PTHREAD_MUTEX_NORMAL = PTHREAD_MUTEX_TIMED_NP,
  PTHREAD_MUTEX_RECURSIVE = PTHREAD_MUTEX_RECURSIVE_NP,
  PTHREAD_MUTEX_ERRORCHECK = PTHREAD_MUTEX_ERRORCHECK_NP,
  PTHREAD_MUTEX_DEFAULT = PTHREAD_MUTEX_NORMAL
#endif
#ifdef __USE_GNU
  /* For compatibility.  */
  , PTHREAD_MUTEX_FAST_NP = PTHREAD_MUTEX_TIMED_NP
#endif
};

The following example verifies the recursive mutex.

The example is simple: create two threads in the main function, fn1 in thread 1, lock mutex twice, but unlock only once.Thread fn2 cannot lock the mutex, causing it to remain blocked at position 1.

To enable thread fn1 to lock the mutex first, the sleep function is called in fn2 to sleep fn2 for one second, so fn1 can lock the mutex first.

By removing the comment at position 2, fn2 can lock the mutex and the program will not be deadlocked.

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <string.h>
#include <signal.h>

pthread_mutex_t mt;
int i = 0;

void* fn1(void* agr)
{
  int err;

  pthread_mutex_lock(&mt);
  if((err = pthread_mutex_lock(&mt)) < 0)
  {
    printf("%s\n", strerror(err));
    exit(1);
  }

  ++i;
  printf("%d\n", i);

  //pthread_mutex_unlock(&mt);//-------②
  pthread_mutex_unlock(&mt);
}

void* fn2(void* arg)
{
  sleep(1);//The goal is for thread fn1 to execute first.
  pthread_mutex_lock(&mt);//-----------①
  ++i;
  printf("second %d\n", i);
  pthread_mutex_unlock(&mt);
}

int main()
{
  pthread_t tid1, tid2;

  pthread_mutexattr_t mat;
  pthread_mutexattr_init(&mat);

  //The type of lock set is recursive
  pthread_mutexattr_settype(&mat, PTHREAD_MUTEX_RECURSIVE);
  pthread_mutex_init(&mt, &mat);
    
  pthread_create(&tid1, NULL, fn1, NULL);
  pthread_create(&tid2, NULL, fn2, NULL);

  pthread_join(tid1, NULL);
  pthread_join(tid2, NULL);

  pthread_mutex_destroy(&mt);
}
c/c++ Learning Mutual Assistance QQ Group: 877684253 I WeChat: xiaoshitou5854

Posted by dopp on Fri, 27 Mar 2020 21:49:11 -0700