UNIX环境高级编程——互斥量属性
互斥量具有一些属性,通过修改这些属性可以控制锁的一些行为。缺省的互斥锁属性及其值如下:
- pshared: PTHREAD_PROCESS_PRIVATE
- type: PTHREAD_MUTEX_DEFAULT
- protocol: PTHREAD_PRIO_NONE
- prioceiling: –
- robustness: PTHREAD_MUTEX_STALLED_NP
pthread_mutexattr_t attr;
int pthread_mutexattr_init(pthread_mutexattr_t *attr);
int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);
int pthread_mutexattr_getpshared(pthread_mutexattr_t *attr,int *pshared);
int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);
参数:pshared的取值可以是: PTHREAD_PROCESS_SHARED,PTHREAD_PROCESS_PRIVATE
说明:如果互斥锁属性对象的pshared属性被置PTHREAD_PROCESS_SHARED。那么由这个属性对象创建的互斥锁将被保存在共享内存中,可以被多个进程中的线程共享。如pshared属性被置为PTHREAD_PROCESS_PRIVATE,那么只有和创建这个互斥锁的线程在同一个进程中的线程才能访问这个互斥锁。
2.获得/修改类型互斥量属性
int pthread_mutexattr_settype(pthread_mutexattr_t *attr,int kind);
int pthread_mutexattr_gettype(pthread_mutexattr_t *attr,int *kind);
- PTHREAD_MUTEX_DEFAULT(缺省的互斥锁类型属性):这种类型的互斥锁不会自动检测死锁。如果一个线程试图对一个互斥锁重复锁定,将会引起不可预料的结果。如果试图解锁一个由别的线程锁定的互斥锁会引发不可预料的结果。如果一个线程试图解锁已经被解锁的互斥锁也会引发不可预料的结果。POSIX标准规定,对于某一具体的实现,可以把这种类型的互斥锁定义为其他类型的互斥锁。
- PTHREAD_MUTEX_NORMAL:这种类型的互斥锁不会自动检测死锁。如果一个线程试图对一个互斥锁重复锁定,将会引起这个线程的死锁。如果试图解锁一个由别的线程锁定的互斥锁会引发不可预料的结果。如果一个线程试图解锁已经被解锁的互斥锁也会引发不可预料的结果。
- PTHREAD_MUTEX_ERRORCHECK:这种类型的互斥锁会自动检测死锁。 如果一个线程试图对一个互斥锁重复锁定,将会返回一个错误代码。 如果试图解锁一个由别的线程锁定的互斥锁将会返回一个错误代码。如果一个线程试图解锁已经被解锁的互斥锁也将会返回一个错误代码。
- PTHREAD_MUTEX_RECURSIVE:如果一个线程对这种类型的互斥锁重复上锁,不会引起死锁。一个线程对这类互斥锁的多次重复上锁必须由这个线程来重复相同数量的解锁,这样才能解开这个互斥锁,别的线程才能得到这个互斥锁。如果试图解锁一个由别的线程锁定的互斥锁将会返回一个错误代码。如果一个线程试图解锁已经被解锁的互斥锁也将会返回一个错误代码。这种类型的互斥锁只能是进程私有的(作用域属性为PTHREAD_PROCESS_PRIVATE)。
3.设置/获取互斥锁的协议属性
int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);
互斥锁协议属性的可能值及其含义:
- PTHREAD_PRIO_NONE:线程的优先级和调度不会受到互斥锁拥有权的影响。
- PTHREAD_PRIO_INHERIT:当高优先级的等待低优先级的线程锁定互斥量时,低优先级的线程以高优先级线程的优先级运行。这种方式将以继承的形式传递。当线程解锁互斥量时,线程的优先级自动被将到它原来的优先级。(“优先级继承”意味着,当一个线程在由另一个低优先级线程拥有的互斥量上等待时,后者的优先级将被增加到等待线程的优先级.)
- PTHREAD_PRIO_PROTECT:拥有该类型的互斥量的线程将以自己的优先级和它拥有的互斥量的线程将以自己的优先级和它拥有的互斥量的优先级较高者运行,其他等待该线程拥有的锁得线程对该线程的调度优先级没有影响。
注意:PTHREAD_PRIO_INHERIT 和 PTHREAD_PRIO_PROTECT 只有在采用实时调度策略SCHED_FIFO 或SCHED_RR的优先级进程内可用。
一个线程可以同时拥有多个混合使用PTHREAD_PRIO_INHERIT 和PTHREAD_PRIO_PROTECT协议属性初始化的互斥锁。在这种情况下,该线程将以通过其中任一协议获取的最高优先级执行。pthread_mutexattr_getprotocol可用来获取互斥锁属性对象的协议属性。
4.设置/获取互斥锁属性对象的优先级上限属性
int pthread_mutexattr_setprioceiling(pthread_mutexatt_t *attr, int prioceiling, int *oldceiling);
int pthread_mutexattr_getprioceiling(const pthread_mutexatt_t *attr, int *prioceiling);
prioceiling指定已初始化互斥锁的优先级上限。优先级上限定义执行互斥锁保护的临界段时的最低优先级。prioceiling 位于SCHED_FIFO 所定义的优先级的最大范围内。要避免优先级倒置,请将prioceiling 设置为高于或等于可能会锁定特定互斥锁的所有线程的最高优先级。oldceiling 用于返回以前的优先级上限值。
pthread_mutex_setprioceiling可更改互斥锁mutex的优先级上限prioceiling。
pthread_mutex_setprioceiling可锁定互斥锁(如果未锁定的话),或者一直处于阻塞状态,直到它成功锁定该互斥锁,更改该互斥锁的优先级上限并将该互斥锁释放为止。锁定互斥锁的过程无需遵循优先级保护协议。
如果 pthread_mutex_setprioceiling成功,则将在 old_ceiling 中返回以前的优先级上限值。如果pthread_mutex_setprioceiling失败,则互斥锁的优先级上限保持不变。pthread_mutex_getprioceiling会返回mutex 的优先级上限prioceiling。
注意:“优先级上限”协议意味着当一个线程拥有互斥量时,它将以指定的优先级运行。
5.设置/获取互斥锁的强健属性
int pthread_mutexattr_setrobust_np(pthread_mutexattr_t *attr, int *robustness);
int pthread_mutexattr_getrobust_np(const pthread_mutexattr_t *attr, int *robustness);
robustness 定义在互斥锁的持有者“死亡”时的行为。pthread.h 中定义的robustness 的值为PTHREAD_MUTEX_ROBUST_NP 或 PTHREAD_MUTEX_STALLED_NP。缺省值为PTHREAD_MUTEX_STALLED_NP。
- PTHREAD_MUTEX_STALLED_NP: 如果互斥锁的持有者死亡,则以后对pthread_mutex_lock() 的所有调用将以不确定的方式被阻塞。
- PTHREAD_MUTEX_ROBUST_NP: 如果互斥锁的持有者“死亡”了,或者持有这样的互斥锁的进程unmap了互斥锁所在的共享内存或者持有这样的互斥锁的进程执行了exec调用,则会解除锁定该互斥锁。互斥锁的下一个持有者将获取该互斥锁,并返回错误EOWNWERDEAD。
如果互斥锁具有PTHREAD_MUTEX_ROBUST_NP的属性,则应用程序在获取该锁时必须检查pthread_mutex_lock 的返回代码看获取锁时是否返回了EOWNWERDEAD错误。如果是,则
- 互斥锁的新的持有者应使该互斥锁所保护的状态保持一致。因为互斥锁的上一个持有者“死亡”时互斥锁所保护的状态可能出于不一致的状态。
- 如果互斥锁的新的持有者能够使该状态保持一致,请针对该互斥锁调用pthread_mutex_consistent_np(),并解除锁定该互斥锁。
- 如果互斥锁的新的持有者无法使该状态保持一致,请勿针对该互斥锁调用pthread_mutex_consistent_np(),而是解除锁定该互斥锁。所有等待的线程都将被唤醒,以后对pthread_mutex_lock() 的所有调用都将无法获取该互斥锁。返回错误为ENOTRECOVERABLE。
如果一个线程获取了互斥锁,但是获取时得到了EOWNERDEAD的错误,然后它终止并且没有释放互斥锁 ,则下一个持有者获取该锁时将返回代码EOWNERDEAD。
注意:
1、互斥量需要时间来加锁和解锁。锁住较少互斥量的程序通常运行得更快。所以,互斥量应该尽量少,够用即可,每个互斥量保护的区域应则尽量大。
2、互斥量的本质是串行执行。如果很多线程需要频繁地加锁同一个互斥量,则线程的大部分时间就会在等待,这对性能是有害的。如果互斥量保护的数据(或代码)包含彼此无关的片段,则可以特大的互斥量分解为几个小的互斥量来提高性能。这样,任意时刻需要小互斥量的线程减少,线程等待时间就会减少。所以,互斥量应该足够多(到有意义的地步),每个互斥量保护的区域则应尽量的少。
3、POSIX线程锁机制的Linux实现都不是取消点,因此,延迟取消类型的线程不会因收到取消信号而离开加锁等待。
4、线程在加锁后解锁前被取消,锁将永远保持锁定状态。因此如果在关键区段内有取消点存在,或者设置了异步取消类型,则必须在退出回调函数中解锁。
5、锁机制不是异步信号安全的,也就是说,不应该在信号处理过程中使用互斥锁,否则容易造成死锁。
本文来源于以前写的博客:《posix多线程有感--线程高级编程(互斥量属性)》,并做部分修改。
UNIX环境高级编程——互斥量属性的更多相关文章
- UNIX环境高级编程——线程属性
pthread_attr_t 的缺省属性值 属性 值 结果 scope PTHREAD_SCOPE_PROCESS 新线程与进程中的其他线程发生竞争. detachstate PTHREAD_CREA ...
- (九) 一起学 Unix 环境高级编程 (APUE) 之 线程
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (十) 一起学 Unix 环境高级编程 (APUE) 之 线程控制
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- (十二) 一起学 Unix 环境高级编程 (APUE) 之 进程间通信(IPC)
. . . . . 目录 (一) 一起学 Unix 环境高级编程 (APUE) 之 标准IO (二) 一起学 Unix 环境高级编程 (APUE) 之 文件 IO (三) 一起学 Unix 环境高级编 ...
- 《UNIX环境高级编程(第3版)》
<UNIX环境高级编程(第3版)> 基本信息 原书名:Advanced Programming in the UNIX Environment (3rd Edition) (Addison ...
- UNIX环境高级编程——管道读写规则和pipe Capacity、PIPE_BUF
一.当没有数据可读时O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止. O_NONBLOCK enable:read调用返回-1,errno值为EAGAI ...
- 【UNIX环境高级编程】线程同步
当多个线程共享相同的内存时,需要确保每个线程看到一致的数据视图.如果每个线程使用的变量都是其他线程不会读取和修改的,那么就不存在一致性问题.同样,如果变量是只读的也不会有一致性问题.但是,当一个线程可 ...
- UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数
UNIX环境高级编程——TCP/IP网络编程 常用网络信息检索函数 gethostname() getppername() getsockname() gethostbyname() ...
- unix环境高级编程基础知识之第二篇(3)
看了unix环境高级编程第三章,把代码也都自己敲了一遍,另主要讲解了一些IO函数,read/write/fseek/fcntl:这里主要是c函数,比较容易,看多了就熟悉了.对fcntl函数讲解比较到位 ...
随机推荐
- 用 ConfigMap 管理配置 - 每天5分钟玩转 Docker 容器技术(159)
Secret 可以为 Pod 提供密码.Token.私钥等敏感数据:对于一些非敏感数据,比如应用的配置信息,则可以用 ConfigMap. ConfigMap 的创建和使用方式与 Secret 非常类 ...
- 如何避免 async/await 地狱
简评:async/await 写着很爽,不过要注意这些问题. async/await 让我们摆脱了回调地狱,但是这又引入了 async/await 地狱的问题. 什么是 async/await 地狱 ...
- Elasticsearch 学习(一):入门
一.概念 Elasticsearch 是一个实时分布式搜索和分析引擎.它用于全文搜索.结构化搜索.分析以及将这三者混合使用. 维基百科.英国卫报.StackOverflow.Github 等公司都在使 ...
- Nginx+Tomca+Redis实现负载均衡、资源分离、session共享
目标实现:Nginx作为负载均衡后端多Tomcat实例,通过Redis实现Session共享. 操作系统环境:CentOS 6.8 SSH:SecureCRT 其中 Nginx服务:80端口 Tomc ...
- JVM内存模型及分区
Java虚拟机在程序执行过程会把jvm的内存分为若干个不同的数据区域来管理,这些区域有自己的用途,以及创建和销毁时间. JVM内存模型如下图所示: jvm管理的内存区域包括以下几个区域: 栈区: 栈 ...
- Python小代码_12_生成前 n 行杨辉三角
def demo(t): print([1]) print([1, 1]) line = [1, 1] for i in range(2, t): r = [] for j in range(0, l ...
- React-报错Warning:setState(...)on anunmounted component
一.原因 这种错误一般出现在react组件已经从DOM中移除.我们在react组件中发送一些异步请求的时候,就可能会出现这样的问题.举个例子,我们在componentWillMount中 ...
- CentOS6.8虚拟机安装及ORALCE安装记录
CENTOS6.8安装数据库及设置自启动脚本教程 作者:张欣橙 本文所需要的所有参数均位于文末附录中 一.新建虚拟机 选择下一步 选择下一步 选择稍后安装操作系统 选择LINUX 版本 CentOS ...
- 安装oracle时修改Linux版本问题
Linux安装Oracle报Checking operating system version must be redhat, SuSE, redhat, UnitedLinux or asianux ...
- python中的函数(定义、多个返回值、默认参数、参数组)
函数定义 在python中函数的定义以及调用如下代码所示: def test(x): y = x+1 return y result = test(2) print(result) 多个返回值的情况 ...