互斥锁的robust属性的介绍和使用

一个具体的场景:在多线程中,当一个线程获得锁之后异常退出后,应该怎么处理?

方案一 使用锁的robust特性

简单地讲,就是当拥有这个锁的线程挂了后,下一个尝试去获得锁的线程会得到EOWNWERDEAD的返回值,新的拥有者应该再去调用pthread_mutex_consistent_np()来保持锁状态的一致性,并解锁。

直接上代码看示例:

  1 /*================================================================
  2  *   Copyright (C) 2019 Ltd. All rights reserved.
  3  *   
  4  *   File Name :robust_mutex.c
  5  *   Author    :Hamilton
  6  *   Date      :2019-07-30
  7  *   Descriptor:
  8  *
  9  ================================================================*/
 10 
 11 #include <stdlib.h>
 12 #include <stdio.h>
 13 #include <unistd.h>
 14 #include <pthread.h>
 15 #include <errno.h>
 16 
 17 #define handle_error_en(en, msg) \
 18     do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
 19 
 20 static pthread_mutex_t mtx;
 21 
 22 static void *original_owner_thread(void *ptr)
 23 {
 24     printf("\n[original owner] Setting lock...\n");
 25     pthread_mutex_lock(&mtx);
 26     printf("[original owner] Locked. Now exiting without unlocking.\n");
 27     pthread_exit(NULL);
 28 }
 29 static void *bad_thread(void *ptr)
 30 {
 31     printf("\n[bad owner] Setting lock...\n");
 32     pthread_mutex_lock(&mtx);
 33     printf("[bad owner] Locked. Now exiting without unlocking.\n");
 34     pthread_exit(NULL);
 35 }
 36 static void *second_thread(void *ptr)
 37 {
 38     int i = 5;
 39 
 40     while (i--)
 41     {
 42         int s = pthread_mutex_lock(&mtx);
 43 
 44         if (s == EOWNERDEAD) 
 45         {
 46             printf("\n[second thread] pthread_mutex_lock() returned EOWNERDEAD\n");
 47 
 48             printf("[second thread] Now make the mutex consistent\n");
 49             s = pthread_mutex_consistent(&mtx);
 50             if (s != 0)
 51                 handle_error_en(s, "pthread_mutex_consistent");
 52 
 53             printf("[second thread] Mutex is now consistent; unlocking\n");
 54             s = pthread_mutex_unlock(&mtx);
 55             if (s != 0)
 56                 handle_error_en(s, "pthread_mutex_unlock");
 57 
 58         } 
 59         else if (s < 0)
 60         {
 61             printf("\n[second thread] pthread_mutex_lock() unexpectedly failed\n");
 62             handle_error_en(s, "pthread_mutex_lock");
 63         }
 64         else 
 65         {
 66             printf("\n[second thread] pthread_mutex_lock success.\n");
 67             printf("do somthing.... \n");
 68             s = pthread_mutex_unlock(&mtx);
 69             if (s != 0)
 70                 handle_error_en(s, "pthread_mutex_unlock");
 71         }
 72         sleep(1);
 73     }
 74 
 75     pthread_exit(NULL);
 76 }
 77 
 78 int main(int argc, char *argv[])
 79 {
 80     pthread_t thr;
 81     pthread_mutexattr_t attr;
 82     int s;
 83 
 84     pthread_mutexattr_init(&attr);
 85     /* initialize the attributes object */
 86     pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
 87     /* set robustness */
 88 
 89     pthread_mutex_init(&mtx, &attr);   /* initialize the mutex */
 90 
 91     pthread_create(&thr, NULL, original_owner_thread, NULL);
 92 
 93     sleep(1);
 94     pthread_create(&thr, NULL, second_thread, NULL);
 95     sleep(1);
 96     pthread_create(&thr, NULL, bad_thread, NULL);
 97 
 98     /* "original_owner_thread" should have exited by now */
 99 
100     int i = 5;
101     while(i--)
102     {
103         s = pthread_mutex_lock(&mtx);
104 
105         if (s == EOWNERDEAD) 
106         {
107             printf("\n[main thread] pthread_mutex_lock() returned EOWNERDEAD\n");
108 
109             printf("[main thread] Now make the mutex consistent\n");
110             s = pthread_mutex_consistent(&mtx);
111             if (s != 0)
112                 handle_error_en(s, "pthread_mutex_consistent");
113 
114             printf("[main thread] Mutex is now consistent; unlocking\n");
115             s = pthread_mutex_unlock(&mtx);
116             if (s != 0)
117                 handle_error_en(s, "pthread_mutex_unlock");
118 
119         } 
120         else if (s < 0)
121         {
122             printf("\n[main thread] pthread_mutex_lock() unexpectedly failed\n");
123             handle_error_en(s, "pthread_mutex_lock");
124         }
125         else 
126         {
127             printf("\n[main thread] pthread_mutex_lock success.\n");
128             printf("do somthing.... \n");
129             s = pthread_mutex_unlock(&mtx);
130             if (s != 0)
131                 handle_error_en(s, "pthread_mutex_unlock");
132         }
133 
134         sleep(1);
135     }
136     exit(EXIT_SUCCESS);
137 }

 

示例中总共包含四个线程,original_owner_thread() 和 bad_thread() 两个线程获得锁后立马退出不释放,其它两个线程main thread 及 second_thread() 轮流抢占锁,并对锁的异常进行恢复处理,看下打印结果:

是不是很简单,通过设置robust特性,并在每次获取锁时判断锁的异常状态,便能很好的处理锁异常退出的情况。

关于锁的robust特性及consistent设定,可参考以下更多资料:

https://docs.oracle.com/cd/E19455-01/806-5257/6je9h032m/index.html

http://pubs.opengroup.org/onlinepubs/9699919799/functions/pthread_mutex_consistent.html

本文示例改编自:http://manpages.ubuntu.com/manpages/bionic/man3/pthread_mutexattr_setrobust.3.html

 

后记:再看看进程间有没有类似的机制,但是google并没有找到相关介绍,便想看看pthreas_mutex_lock这套机制在process下工作是否正常,先看示例代码:

  1 /*================================================================
  2  *   Copyright (C) 2019 Ltd. All rights reserved.
  3  *   
  4  *   File Name :robust_mutex.c
  5  *   Author    :Hamilton
  6  *   Date      :2019-07-30
  7  *   Descriptor:
  8  *
  9  ================================================================*/
 10 
 11 #include <stdlib.h>
 12 #include <stdio.h>
 13 #include <unistd.h>
 14 #include <pthread.h>
 15 #include <errno.h>
 16 #include <sys/mman.h>
 17 #include <fcntl.h>
 18 #include <sys/types.h>
 19 #include <sys/stat.h>
 20 
 21 #define SHM_NAME    "fasdfasfasfas"
 22 
 23 
 24 #define handle_error_en(en, msg) \
 25     do { errno = en; perror(msg); exit(EXIT_FAILURE); } while (0)
 26 
 27 static pthread_mutex_t *mtx;
 28 static int fd_shm;
 29 
 30 void shm_mutex_init(pthread_mutex_t  **mutex)
 31 { 
 32     pthread_mutexattr_t attr;
 33 
 34     pthread_mutexattr_init(&attr);
 35     /* initialize the attributes object */
 36     pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
 37     /* set robustness */
 38 
 39     // Get shared memory
 40     if ((fd_shm = shm_open (SHM_NAME, O_RDWR | O_CREAT, 0660)) == -1)
 41         perror ("shm_open");
 42 
 43     if (ftruncate (fd_shm, sizeof (pthread_mutex_t)) == -1)
 44         perror ("ftruncate");
 45 
 46     if ((*mutex = mmap (NULL, sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED,
 47                     fd_shm, 0)) == MAP_FAILED)
 48         perror ("mmap");
 49 
 50     pthread_mutex_init(*mutex, &attr);   /* initialize the mutex */
 51 }
 52 int main(int argc, char *argv[])
 53 {
 54     int s;
 55 
 56     shm_mutex_init(&mtx);
 57 
 58     if ((s = fork()) < 0)
 59     {
 60         perror("fork.");    
 61     }
 62     else if (s == 0) // child
 63     {
 64         sleep(1);
 65             printf("\n[bad owner] Setting lock...\n");
 66             pthread_mutex_lock(mtx);
 67             printf("[bad owner] Locked. Now exiting without unlocking.\n");
 68     }
 69     else
 70     {
 71         int i = 5;
 72         while(i--)
 73         {
 74             s = pthread_mutex_lock(mtx);
 75 
 76             if (s == EOWNERDEAD) 
 77             {
 78                 printf("\n[main thread] pthread_mutex_lock() returned EOWNERDEAD\n");
 79 
 80                 printf("[main thread] Now make the mutex consistent\n");
 81                 s = pthread_mutex_consistent(mtx);
 82                 if (s != 0)
 83                     handle_error_en(s, "pthread_mutex_consistent");
 84 
 85                 printf("[main thread] Mutex is now consistent; unlocking\n");
 86                 s = pthread_mutex_unlock(mtx);
 87                 if (s != 0)
 88                     handle_error_en(s, "pthread_mutex_unlock");
 89 
 90             } 
 91             else if (s < 0)
 92             {
 93                 printf("\n[main thread] pthread_mutex_lock() unexpectedly failed\n");
 94                 handle_error_en(s, "pthread_mutex_lock");
 95             }
 96             else 
 97             {
 98                 printf("\n[main thread] pthread_mutex_lock success.\n");
 99                 printf("do somthing.... \n");
100                 s = pthread_mutex_unlock(mtx);
101                 if (s != 0)
102                     handle_error_en(s, "pthread_mutex_unlock");
103             }
104 
105             sleep(1);
106         }
107     }
108     exit(EXIT_SUCCESS);
109 }

 

 编译执行下看看:

进程间通信的锁得放在共享内存中,编译运行OK,也能正常工作。

 

posted @ 2019-08-05 11:19  ba哥  阅读(1914)  评论(0编辑  收藏  举报