C recursive mutex

Time:2021-3-1

Before talking about recursive mutexes, let’s talk about the mutexes. In the third edition of APUE, there are four kinds of mutexes

  • PTHREAD_ MUTEX_ Normal: standard type, without any special error checking or deadlock detection.

    Deadlock occurs when a mutex that has not been unlocked is locked 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. When the number of times to unlock and lock is not the same, the lock will not be released, and other threads will not be able to lock the mutex.

  • PTHREAD_ MUTEX_ Errorcheck: provides error detection. If a mutex that has not been unlocked is locked in the same thread, an error will be reported. But in centos7 (3.10.0-957. EL7. X86)_ 64), GCC 4.8.5 20150623 (red hat 4.8.5-39),Discovery: to lock a mutex that has not been unlocked in the same thread, no error is reported.

  • PTHREAD_MUTEX_DEFAULT

In pthread. H in GCC 4.8.5 20150623 (red hat 4.8.5-39), the definition of mutex type is 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 very simple. Create two threads in the main function. In the function FN1 of thread 1, lock the mutex twice, but unlock it only once. Thread FN2 is unable to lock mutex, causing it to block at (1).

In order to enable the thread FN1 to lock the mutex first, the sleep function is called in FN2 to let FN2 sleep for one second, so FN1 can lock the mutex first.

Remove the comment at (2), FN2 can lock mutex, and the program will not appear deadlock state.

#include 
#include 
#include 
#include 
#include 

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 purpose is to let thread FN1 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);

  //Set the type of lock to recursive lock
  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 QQ group: 877684253