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

方案一 使用锁的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 ()
  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 = ;
  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 != )
  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 != )
  56. handle_error_en(s, "pthread_mutex_unlock");
  57.  
  58. }
  59. else if (s < )
  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 != )
  70. handle_error_en(s, "pthread_mutex_unlock");
  71. }
  72. sleep();
  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();
  94. pthread_create(&thr, NULL, second_thread, NULL);
  95. sleep();
  96. pthread_create(&thr, NULL, bad_thread, NULL);
  97.  
  98. /* "original_owner_thread" should have exited by now */
  99.  
  100. int i = ;
  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 != )
  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 != )
  117. handle_error_en(s, "pthread_mutex_unlock");
  118.  
  119. }
  120. else if (s < )
  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 != )
  131. handle_error_en(s, "pthread_mutex_unlock");
  132. }
  133.  
  134. sleep();
  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. #define handle_error_en(en, msg) \
  24. do { errno = en; perror(msg); exit(EXIT_FAILURE); } while ()
  25.  
  26. static pthread_mutex_t *mtx;
  27. static int fd_shm;
  28.  
  29. void shm_mutex_init(pthread_mutex_t **mutex)
  30. {
  31. pthread_mutexattr_t attr;
  32.  
  33. pthread_mutexattr_init(&attr);
  34. /* initialize the attributes object */
  35. pthread_mutexattr_setrobust(&attr, PTHREAD_MUTEX_ROBUST);
  36. /* set robustness */
  37.  
  38. // Get shared memory
  39. if ((fd_shm = shm_open (SHM_NAME, O_RDWR | O_CREAT, )) == -)
  40. perror ("shm_open");
  41.  
  42. if (ftruncate (fd_shm, sizeof (pthread_mutex_t)) == -)
  43. perror ("ftruncate");
  44.  
  45. if ((*mutex = mmap (NULL, sizeof (pthread_mutex_t), PROT_READ | PROT_WRITE, MAP_SHARED,
  46. fd_shm, )) == MAP_FAILED)
  47. perror ("mmap");
  48.  
  49. pthread_mutex_init(*mutex, &attr); /* initialize the mutex */
  50. }
  51. int main(int argc, char *argv[])
  52. {
  53. int s;
  54.  
  55. shm_mutex_init(&mtx);
  56.  
  57. if ((s = fork()) < )
  58. {
  59. perror("fork.");
  60. }
  61. else if (s == ) // child
  62. {
  63. sleep();
  64. printf("\n[bad owner] Setting lock...\n");
  65. pthread_mutex_lock(mtx);
  66. printf("[bad owner] Locked. Now exiting without unlocking.\n");
  67. }
  68. else
  69. {
  70. int i = ;
  71. while(i--)
  72. {
  73. s = pthread_mutex_lock(mtx);
  74.  
  75. if (s == EOWNERDEAD)
  76. {
  77. printf("\n[main thread] pthread_mutex_lock() returned EOWNERDEAD\n");
  78.  
  79. printf("[main thread] Now make the mutex consistent\n");
  80. s = pthread_mutex_consistent(mtx);
  81. if (s != )
  82. handle_error_en(s, "pthread_mutex_consistent");
  83.  
  84. printf("[main thread] Mutex is now consistent; unlocking\n");
  85. s = pthread_mutex_unlock(mtx);
  86. if (s != )
  87. handle_error_en(s, "pthread_mutex_unlock");
  88.  
  89. }
  90. else if (s < )
  91. {
  92. printf("\n[main thread] pthread_mutex_lock() unexpectedly failed\n");
  93. handle_error_en(s, "pthread_mutex_lock");
  94. }
  95. else
  96. {
  97. printf("\n[main thread] pthread_mutex_lock success.\n");
  98. printf("do somthing.... \n");
  99. s = pthread_mutex_unlock(mtx);
  100. if (s != )
  101. handle_error_en(s, "pthread_mutex_unlock");
  102. }
  103.  
  104. sleep();
  105. }
  106. }
  107. exit(EXIT_SUCCESS);
  108. }

编译执行下看看:

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

互斥锁的robust属性的介绍和使用的更多相关文章

  1. linux c学习笔记----互斥锁属性

    转自:http://lobert.iteye.com/blog/1762844 互斥锁属性 使用互斥锁(互斥)可以使线程按顺序执行.通常,互斥锁通过确保一次只有一个线程执行代码的临界段来同步多个线程. ...

  2. 四十、Linux 线程——互斥锁和读写锁

    40.1 互斥锁 40.1.1 介绍 互斥锁(mutex)是一种简单的加锁的方法来控制对共享资源的访问. 在同一时刻只能有一个线程掌握某个互斥锁,拥有上锁状态的线程能够对共享资源进行访问. 若其他线程 ...

  3. 【Linux C 多线程编程】互斥锁与条件变量

    一.互斥锁 互斥量从本质上说就是一把锁, 提供对共享资源的保护访问. 1) 初始化: 在Linux下, 线程的互斥量数据类型是pthread_mutex_t. 在使用前, 要对它进行初始化: 对于静态 ...

  4. 【转载】同步和互斥的POSIX支持(互斥锁,条件变量,自旋锁)

    上篇文章也蛮好,线程同步之条件变量与互斥锁的结合: http://www.cnblogs.com/charlesblc/p/6143397.html   现在有这篇文章: http://blog.cs ...

  5. 互斥锁属性PTHREAD_MUTEX_RECURSIVE

    四.互斥锁属性 线程和线程的同步对象(互斥量,读写锁,条件变量)都具有属性.在修改属性前都需要对该结构进行初始化.使用后要把该结构回收.我们用pthread_ mutexattr_init函数对pth ...

  6. 创建进程,join方法,进程对象相关属性和方法,僵尸进程和孤儿进程,守护进程,互斥锁

    创建进程 在python中提供了一个multiprocessing模块可以帮助我们使用多进程解决问题.在multiprocessing 模块中有一个类Process. from multiproces ...

  7. Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等

    Java 中15种锁的介绍 Java 中15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁,乐观锁,分段锁,自旋锁等等,在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类 ...

  8. 8.12 day31 进程间通信 Queue队列使用 生产者消费者模型 线程理论 创建及对象属性方法 线程互斥锁 守护线程

    进程补充 进程通信 要想实现进程间通信,可以用管道或者队列 队列比管道更好用(队列自带管道和锁) 管道和队列的共同特点:数据只有一份,取完就没了 无法重复获取用一份数据 队列特点:先进先出 堆栈特点: ...

  9. Java 种15种锁的介绍:公平锁,可重入锁,独享锁,互斥锁等等…

    Java 中15种锁的介绍 1,在读很多并发文章中,会提及各种各样的锁,如公平锁,乐观锁,下面是对各种锁的总结归纳: 公平锁/非公平锁 可重入锁/不可重入锁 独享锁/共享锁 互斥锁/读写锁 乐观锁/悲 ...

随机推荐

  1. 浅谈Asp.Net中的几种传值方式

    一.使用Querystring Querystring是一种非常简单的传值方式,其缺点就是会把要传送的值显示在浏览器的地址栏中,并且在此方法中不能够传递对象.如果你想传递一个安全性不是那么太重要或者是 ...

  2. oracle用dba创建用户并授权

    参考: https://blog.csdn.net/zhang195617/article/details/5857769 sqlplus中切换用户,如切换到adm用户,命令为:conn adm/12 ...

  3. Java集合详解8:Java集合类细节精讲,细节决定成败

    <Java集合详解系列>是我在完成夯实Java基础篇的系列博客后准备开始写的新系列. 这些文章将整理到我在GitHub上的<Java面试指南>仓库,更多精彩内容请到我的仓库里查 ...

  4. caffe解析

    Caffe支持CUDA,Caffe和TensorFlow没有给出分布式的版本, 可以使用多gpu,Caffe通过直接在执行指令后面加上-gpu 0,1

  5. 利用ffmpeg获取视频帧

    如果要对视频帧进行处理,可以先把视频帧读取出来. sh文件代码如下: #!/usr/bin/env sh VIDEO=/home/xxx/video/ FRAMES=/home/xxx/frame/ ...

  6. ef core 全局过滤

    有些固定的条件,基本每个查询的时候需要带的条件,我们可以使用全局过滤来帮我们,这样后面的查询就不用每次都带条件了. 微软自带的:https://docs.microsoft.com/zh-cn/ef/ ...

  7. spark 操作hive

    1.hive动态分区,只需进行以下设置 val spark = SparkSession.builder() .appName("hivetest") .master(" ...

  8. 高系统的分布性有状态的中间层Actor模型

    写在前面 https://www.cnblogs.com/gengzhe/p/ray_actor.html Orleans是基于Actor模型思想的.NET领域的框架,它提供了一种直接而简单的方法来构 ...

  9. Python学习教程(十)精选 TOP45 值得学习的Python项目

    精选 TOP45 值得学习的Python项目 [导读]热门资源博客 Mybridge AI 比较了 18000 个关于 Python 的项目,并从中精选出 45 个最具竞争力的项目.我们进行了翻译,在 ...

  10. [转帖]如何获得一个Oracle RAC数据库(从Github - oracle/vagrant-boxes) --- 暂时未测试成功 公司网络太差了..

    如何获得一个Oracle RAC数据库(从Github - oracle/vagrant-boxes) 2019-11-20 16:40:36 dingdingfish 阅读数 5更多 分类专栏: 如 ...