pthread的lowlevellock
pthread的lowlevellock是futex的最简单的锁应用。也是pthread其它同步原语最基本的锁。lowlevellock提供(或实现)了三种锁(方法),一是基于0或1的互斥的锁规则,二是基于robust futex定义的锁规则,三是用于condition重新对临界区上锁的操作。
lowlevellock使用的是non-pi futex。futex的锁规则由用户空间来定义,这里的用户空间是glibc。
normal lowlevellock 定义的0或1互斥的futex锁规则为:
0,锁无持有者。
1,锁有持有者。
2,锁竞争。
两个锁操作 __lll_lock 和 __lll_unlock。
上锁操作 __lll_lock:
使用atomic_compare_and_exchange尝试对futex上锁,如果这时锁状态为0,完成上锁,futex标记状态为1;否则必须标记futex为锁竞争状态,转而进入锁竞争等待,调用futex系统调用的futex_wait操作进行排队。因为用户空间并不知道内核的futex队列中是否还有其它锁竞争的任务在等待,所以系统调用阻塞唤醒回到用户空间,对futex尝试上锁,必须以锁竞争状态来上锁,以使自己解锁时,会调用futex_wake。
// lll lock fastpath
#define __lll_lock(futex, private) \
((void) \
({ \
int *__futex = (futex); \
if (__glibc_unlikely \
(atomic_compare_and_exchange_bool_acq (__futex, , ))) \
{ \
if (__builtin_constant_p (private) && (private) == LLL_PRIVATE) \
__lll_lock_wait_private (__futex); \
else \
__lll_lock_wait (__futex, private); \
} \
}))
// lll lock slowpath
void
__lll_lock_wait_private (int *futex)
{
if (*futex == )
lll_futex_wait (futex, , LLL_PRIVATE); /* Wait if *futex == 2. */ while (atomic_exchange_acq (futex, ) != )
lll_futex_wait (futex, , LLL_PRIVATE); /* Wait if *futex == 2. */
}
解锁操作 __lll_unlock:
函数在用户空间直接用atomic_exchange将futex状态替换为0,如果发现原来状态为锁竞争,则调用futex系统调用的futex_wake操作,从内核的futex_queue中选出等待任务,将其唤醒,使唤醒的任务回到用户空间完成上锁。
// lll unlock
#define __lll_unlock(futex, private) \
((void) \
({ \
int *__futex = (futex); \
int __private = (private); \
int __oldval = atomic_exchange_rel (__futex, ); \
if (__glibc_unlikely (__oldval > )) \
lll_futex_wake (__futex, , __private); \
}))
上锁操作使用atomic_compare_and_exchange函数进行fastpath尝试,确保与其它锁操作不相容(排它)并且保证状态转换是从0到1,修改可能会失败。
上锁操作使用atomic_exchange函数进行slowpath尝试。slowpath的上锁操作只要修改为锁竞争,并不需要确保锁从何种状态下才能转换状态。当状态从0进行转换,表示无锁,但是现在处理slowpath,表示任务是从锁竞争排队中被唤醒的,可能还有其它任务进行锁竞争而排队。当状态从1进行转换,虽然任务被唤醒了,但是锁被另一任务的fastpath执行偷了,仍然是锁竞争。当状态从2进行转换,无可非议锁竞争。所以在slowpath的上锁操作只要修改为锁竞争状态,并且根据原状态来判断锁的状态转换次序,确认自己是否上锁。
解锁操作使用atomic_exchange直接修改锁状态为无锁。并不需要确保状态转换的关系,也不用参照状态转换的前状态,所以解锁是不会失败的。
__lll_lock_wait函数是上锁操作的 slowpath,它包含了一个循环trylock-wait-loop,在循环中不断重复尝试上锁和失败进行内核排队,直到上锁操作成功被接受。而__lll_unlock解锁操作则对锁进行一次绝对的修改,然后决定是否要进入内核唤醒阻塞的任务。为什么阻塞的任务被唤醒,并不意味这个任务得到了锁,只是被通知解锁事件,这个任务必须再次尝试上锁。为什么被唤醒任务不在内核进行上锁操作,确保锁得到后才返回用户空间,因为处于内核的调用系统并不知道上锁的规则。又由于解锁操作和唤醒阻塞队列是分开的,会futxe唤醒的系统调用也不会理解futex的锁规则,只作单纯的阻塞队列唤醒工作。因此在解锁一刻起,有一线程(运行在另一CPU)发起上锁操作,马上就可以完成上锁,而被__lll_unlock唤醒的任务并没有取得锁,待它回到用户空间时,它尝试上锁就会发现锁被使用了,再次进入内核回到阻塞队列。
robust lowlevellock 使用robust futex定义的锁规则:
futex分为三个状态字段,是否上锁,是否锁竞争,是否持锁线程死。
是否上锁,为整型的0-29位,0代表无锁,非0代表上锁,并且上锁状态同时保存持锁线程的id号。
是否持锁线程死,为整型30位。
是否锁竞争,为整型31位。
两个配对锁操作 __lll_robust_lock 和 __lll_robust_unlock。
它与前的非robust规则的lowlevellock的异同。
一,都使用non-pi futex的futex系统调用操作futex_wait和futex_wake进行锁竞争仲裁。执行系统调用的内核并不理会锁规则,同时上锁和解锁操作都在用户空间进行,内核只进行排队和唤醒。
二,锁都是二态互斥。0代表无锁,非0代表上锁。不同的是robust规则用tid代替非0状态,而非robust规则将上锁为1。
三,robust锁(lowlevellock)将锁竞争状态与上锁状态分开两个字段标记,而非robust锁(lowlevellock)将锁竞争状态作为上锁状态的另一形态。
四,robust锁必须标记持锁线程的生存状态,以供robust算法使用。
五,虽然robust lowlevellock使用了robust锁规则,但并没有提供robust处理服务,同时也没有应用futex提供的robust特性。
我们从代码来比较它们的区别:
normal lowlevellcok 和 robust lowlevellock 在 lock-fastpath 的区别:
相同的算法骨架,先使用atomic_compare_and_exchange函数尝试上锁,确保上锁从状态0转换,失败后进入slowpath。

normal lowlevellcok 和 robust lowlevellock 在 lock-slowpath 的区别:
相同的算法骨架,在循环中尝试上锁,上锁令锁进入锁竞争状态,根据转换前的状态确认自己是否上锁,发现上锁失败后使用futex_wait进入内核进行排队阻塞。
不同的是 robust lowlevellock 使用atomic_compare_and_exchange进行尝试,确保持锁线程的tid不被错入。当发现有锁持有线程死了必须返回,由锁的使用层来进行锁的恢复。

normal lowlevellcok 和 robust lowlevellock 在 unlock 的区别:
两者都通过atomic_exchange直接对锁状态进行修改为0,无视锁当前状态。如果发现锁状态修改前存在锁竞争,进入内核唤醒阻塞任务。
这里注意的是,robust锁unlcok和发生owner died,两种情况是不相容的,因为发生owner died表示任务没机会进行unlock,当任务unlock时不可能owner died,自己不是作为owner现在活得好好的进行unlock。

最后就是用于condition重新进行临界区的上锁操作 __lll_cond_lock。
由于condition是从一个临界区中进入一个条件的阻塞,阻塞在条件变量的期间离开临界区,条件变量通知时重新进入临界区。由于重新进入临界区时,不是通知fastpath上锁,而是从wait_requeue系统调用中返回,相当于slowpath,所以这时的上锁操作与slowpath一样。

pthread的lowlevellock的更多相关文章
- futex-based pthread_cond
pthread_cond的实现使用了几个futex来协同进行同步,以及如何来实现的. 假定你已经明白 futex,futex-requeue,以及 pthread lowlevellock. < ...
- linux 内核的futex
futex是linux内核为用户空间实现锁等同步机制而设计的同步排队(队列queueing)服务.在futex.c的注释中,futex起源于"Fast Userspace Mutex&quo ...
- phtread_mutex 组合
phtread_mutex通过mutexattr设定其类型,并保存在成员__kind中.pthread_mutex的锁操作函数根据__kind进行方法的分派(dispatch).__kind由5个字段 ...
- futex-based pthread_cond 源代码分析
pthread_cond的实现使用了几个futex来协同进行同步,以及如何来实现的. 假定你已经明白 futex,futex-requeue,以及 pthread lowlevellock. < ...
- 4.1/4.2 多线程进阶篇<上>(Pthread & NSThread)
本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 本文源码 Demo 详见 Githubhttps://github.com/shorfng ...
- Windows下使用Dev-C++开发基于pthread.h的多线程程序
一.下载Windows版本的pthread 目前最新版本是:pthreads-w32-2-9-1-release.zip. 二.解压pthread到指定目录 我选择的目录是:E:\DEV-C ...
- NPTL vs PThread
NPTL vs PThread POSIX threads (pthread) is not an implementation, it is a API specification (a stand ...
- Linux pthread
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h& ...
- VS2013 配置pthread
参考:http://blog.csdn.net/qianchenglenger/article/details/16907821 一.下载地址 ftp://sourceware.org/pub/pth ...
随机推荐
- 在线音乐播放器-----酷狗音乐api接口抓取
首先身为一个在线音乐播放器,需要前端和数据库的搭配使用. 在数据库方面,我们没有办法制作,首先是版权问题,再加上数据量.所以我们需要借用其他网络播放器的数据库. 但是这些在线播放器,如百度,酷狗,酷我 ...
- iOS开发之单例模式
1.概述 单例模式是一种常用的软件设计模式,通过单例模式可以保证系统中一个类只有一个实例而且该实例易于外界访问,从而方便对实例个数的控制并节约系统资源. 如果希望系统中某个类的对象只能存在一个,单例模 ...
- 设计模式的征途—1.单例(Singleton)模式
单例模式属于创建型模式的一种,创建型模式是一类最常用的设计模式,在软件开发中应用非常广泛.创建型模式将对象的创建和使用分离,在使用对象时无需关心对象的创建细节,从而降低系统的耦合度,让设计方案更易于修 ...
- Python快速入门(1)
FROM:实验楼 http://python.usyiyi.cn/python_278/tutorial/index.html http://woodpecker.org.cn/abyteofpyth ...
- SharePoint JavaScript 客户端对象使用视频教程
本次视频教程是为大家介绍如何使用SharePoint JavaScript客户端对象,包括对于站点.列表.文档库.列表项.文件夹.文件和附件等基本对象的操作,同时,为大家举几个简单的应用的例子,让大家 ...
- 转:Java中finally和return的执行关系
finally可以分两方面理解 1.执行时机问题.finally总会执行(除非是System.exit()),正常情况下在try后执行,抛异常时在catche后面执行 2.返回值问题.可以认为try( ...
- dispaly属性,position属性
position:absolute;绝对定位相对于父元素(父元素设为relative) position:relative;相对定位相对于自己 position:fixed;固定定位相对于浏览器 di ...
- bootstrap-dialog插件的使用
官网文档:http://nakupanda.github.io/bootstrap3-dialog BootstrapDialog.show({ message: 'Hi Apple!', messa ...
- 性能测试培训:分布式测试之jmeter
性能测试培训:分布式测试之jmeter 在使用Jmeter进行性能测试时,如果并发数比较大(比如最近项目需要支持1000并发),单台电脑的配置(CPU和内存)可能无法支持,这时可以使用Jmeter ...
- Maven项目搭建(三):Maven直接部署项目
上一章给大家讲解了如何使用Maven搭建SSM框架项目. 这次给大家介绍一下怎么使用Maven直接部署项目. Maven直接部署项目 1.新建系统变量CATALINA_HOME,值为:Tom ...