phtread_mutex 组合

时间:2021-11-05 11:32:19

phtread_mutex通过mutexattr设定其类型,并保存在成员__kind中。pthread_mutex的锁操作函数根据__kind进行方法的分派(dispatch)。__kind由5个字段的位属性组成,其中4个字段可以通过mutexattr进行设定。通过属性的组合来决定锁的功能和行为。

phtread_mutex 组合

低4位是基本类型,包括TIMED(有时等待),RECURSIVE(可递归),ERRORCHECK(不可递归),以及ADAPTIVE(有限自旋)。

这4种类型不能组合使用,最三种包含第一种。不论是设定为RECURSIVE,mutex一样都会记录owner的pid。当检测到递归时,TIMED和ADAPTIVE类型不作处理,会造成死锁。而RECURSIVE则作递归锁处理,ERRORCHECK则视为死锁停止进行锁操作,避免死锁。所以RECURSIVE和ERRORCHECK是两种不同方法对待锁递归可能造成的死锁问题。这4种类型的设定与futex的类型无关。

假设你已经明白 futex,pi-futex,pthread lowlevellow,rt_mutex。

<<linux 内核的futex>>

<<linux 内核的futex pi-support,即pi-futex使用rt_mutex委托>>

<<pthread的lowlevellock>>

<<linux 内核的rt_mutex>>

ROBUST属性字段,mutexattr中的mask为0x40000000,而__kind中的mask为0x4,共1位。锁是否需要额外服务,避免锁的持有线程退出而没有释放,造成其它阻塞线程的死锁问题。依赖robust-futex系统调用,由glibc去维护robust list。当一个线程在获得锁的同时,会将mutex链入到这个线程的robust链表中去。当这个线程没死又释放这个锁的之前,就会将mutex从线程的robust链表中摘除。

Protocol属性字段,mutexattr中的mask为0x30000000,而__kind中的mask为0x18,共2位。锁是否需要额外服务,避免优先级逆转的问题。对优先级逆转给出了3种处理协议,第一种不处理,第二种采用PI(优先级继承)算法,依赖pi-futex,第三种采用PP(优先级保护),依赖系统调度器提供的调度策略设定系统调用(sched_setscheduler),以及SCHED_FIFO调度策略。

使用PP协议处理优先级逆转问题时,必须为锁设定一个保护级别的优先级,ceiling。mutexattr中的mask为0x00fff000,而__lock中的mask为0xfff00000,共12位。由于__lock,即futex的高12位被用于存储ceiling,进行PP算法。与robust定义的锁规则不兼容。

Pshared属性字段,mutexattr中的mask为0x80000000,而__kind中的mask为0x20,共1位。锁是否需要进程间共享,即futex是否放在共享内存。这个属性和futex的地址,在内核*同标记为一个futex_key。

elistion属性字段,则没有给出可以设定的接口。由pthread实现库来决定是否实现和使用。

当一个mutex的属性为0时,它等同于一个lowlevellock。

除了设定为PI协议的mutex,使用pi-futex,委托锁操作到rt_mutex。其余的使用futex_wait和futex_wake实现锁竞争服务。

蓝色框是 RECURSIVE 或 ERRORCHECK 的逻辑代码。

红色框是 PI 或 PP 协议依赖的调用。

紫色框是 底层的锁服务。

绿色框是 循环。

trylock:

phtread_mutex 组合

lock:

phtread_mutex 组合

unlock:

phtread_mutex 组合