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 ...
随机推荐
- 查看 NDK 版本
打开Android Studio , 打开左上角的菜单, File => Settings... 打开一个弹窗. 然后在 Appearance & Behavior =>Syst ...
- GitHub中最强大的iOS Notifications和AlertView框架,没有之一!
FFToast是一个非常强大的iOS message notifications和AlertView扩展.它可以很容易实现从屏幕顶部.屏幕底部和屏幕中间弹出一个通知.你可以很容易的自定义弹出的View ...
- Windows 10 Creaters Update 新功能——画中画模式和窗口高斯模糊
在Windows 10 Creaters Update中,可以给窗口设置高斯模糊了,只要几行代码! <Grid Loaded="Grid_Loaded"> <Gr ...
- 走入PHP-变量、运算符
通过define()定义常量: PHP 5.3.0之后,可以使用const关键字在类定义之外定义常量: 下面是PHP的几个魔术变量: PHP支持一个执行运算符:反引号(``),PHP将尝试将反引号中的 ...
- 如何使用ArcGIS发布LiDAR 点云
LiDAR--Light Detection And Ranging,即激光探测与测量技术. 下面将介绍如何使用ARCGIS来发布LiDAR的成果点云数据. LiDAR的点云数据一般格式为LAS.在A ...
- 计算两个date类型的时间差
//两个时间之间分钟差 public static int compareDate(Date d1, Date d2) { // TODO Auto-generated method s ...
- css远距离链接
远距离链接主要运用了hover伪类,但是运用了两次 <!DOCTYPE html> <html lang="en"> <head> <me ...
- C++ 网络爬虫实现
最近有个概念吵得很火,网络爬虫,但是基本都是用什么python或者JAVA写,貌似很少看到用c++写的,我在网上找了一个,看到其实还是很简单的算法 算法讲解:1.遍历资源网站 2.获取html信息 ...
- JDBC基础学习(三)—处理BLOB类型数据
一.BLOB类型介绍 在MySQL中,BLOB是一个二进制的大型对象,可以存储大量数据的容器,它能容纳不同大小的数据. 在MySQL中有四种BLOB类型. 实际使 ...
- matlab实现可调节占空比的方波
我大概讲一下实现的原理:正弦波移相φ,当使得大于sin(φ)的值为1,其他值为-1,占空比就跟这个φ值之间有联系. 占空比原理图如下所示. 结果上图,可以实现调节占空比,方波频率,方波个数. 下面是函 ...