• 互斥锁的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("
    [original owner] Setting lock...
    ");
     25     pthread_mutex_lock(&mtx);
     26     printf("[original owner] Locked. Now exiting without unlocking.
    ");
     27     pthread_exit(NULL);
     28 }
     29 static void *bad_thread(void *ptr)
     30 {
     31     printf("
    [bad owner] Setting lock...
    ");
     32     pthread_mutex_lock(&mtx);
     33     printf("[bad owner] Locked. Now exiting without unlocking.
    ");
     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("
    [second thread] pthread_mutex_lock() returned EOWNERDEAD
    ");
     47 
     48             printf("[second thread] Now make the mutex consistent
    ");
     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
    ");
     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("
    [second thread] pthread_mutex_lock() unexpectedly failed
    ");
     62             handle_error_en(s, "pthread_mutex_lock");
     63         }
     64         else 
     65         {
     66             printf("
    [second thread] pthread_mutex_lock success.
    ");
     67             printf("do somthing.... 
    ");
     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("
    [main thread] pthread_mutex_lock() returned EOWNERDEAD
    ");
    108 
    109             printf("[main thread] Now make the mutex consistent
    ");
    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
    ");
    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("
    [main thread] pthread_mutex_lock() unexpectedly failed
    ");
    123             handle_error_en(s, "pthread_mutex_lock");
    124         }
    125         else 
    126         {
    127             printf("
    [main thread] pthread_mutex_lock success.
    ");
    128             printf("do somthing.... 
    ");
    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("
    [bad owner] Setting lock...
    ");
     66             pthread_mutex_lock(mtx);
     67             printf("[bad owner] Locked. Now exiting without unlocking.
    ");
     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("
    [main thread] pthread_mutex_lock() returned EOWNERDEAD
    ");
     79 
     80                 printf("[main thread] Now make the mutex consistent
    ");
     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
    ");
     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("
    [main thread] pthread_mutex_lock() unexpectedly failed
    ");
     94                 handle_error_en(s, "pthread_mutex_lock");
     95             }
     96             else 
     97             {
     98                 printf("
    [main thread] pthread_mutex_lock success.
    ");
     99                 printf("do somthing.... 
    ");
    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,也能正常工作。

  • 相关阅读:
    JS——几种数组遍历方式总结
    JS——获取浏览器地址栏中的参数
    JQuery——JQuery CSS 选择器
    Maven 配置 本地骨架创建工程
    在SpringBoot中的SpringSecurity的配置类中,http.permitAll()与web.ignoring()的区别
    spring-task定时任务动态配置修改执行时间
    常用加密工具类
    thinkphp3.2 验证码的生成和校验,以及遇到的一些问题
    js 倒计时Demo
    PHP递归函数详解
  • 原文地址:https://www.cnblogs.com/miaoxiong/p/11301910.html
Copyright © 2020-2023  润新知