pthread的lowlevellock

时间:2022-09-14 22:14:23

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。

pthread的lowlevellock

normal lowlevellcok 和 robust lowlevellock 在 lock-slowpath 的区别:

相同的算法骨架,在循环中尝试上锁,上锁令锁进入锁竞争状态,根据转换前的状态确认自己是否上锁,发现上锁失败后使用futex_wait进入内核进行排队阻塞。

不同的是 robust lowlevellock 使用atomic_compare_and_exchange进行尝试,确保持锁线程的tid不被错入。当发现有锁持有线程死了必须返回,由锁的使用层来进行锁的恢复。

pthread的lowlevellock

normal lowlevellcok 和 robust lowlevellock 在 unlock 的区别:

两者都通过atomic_exchange直接对锁状态进行修改为0,无视锁当前状态。如果发现锁状态修改前存在锁竞争,进入内核唤醒阻塞任务。

这里注意的是,robust锁unlcok和发生owner died,两种情况是不相容的,因为发生owner died表示任务没机会进行unlock,当任务unlock时不可能owner died,自己不是作为owner现在活得好好的进行unlock。

pthread的lowlevellock

最后就是用于condition重新进行临界区的上锁操作 __lll_cond_lock

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

pthread的lowlevellock

pthread的lowlevellock的更多相关文章

  1. futex-based pthread_cond

    pthread_cond的实现使用了几个futex来协同进行同步,以及如何来实现的. 假定你已经明白 futex,futex-requeue,以及 pthread lowlevellock. < ...

  2. linux 内核的futex

    futex是linux内核为用户空间实现锁等同步机制而设计的同步排队(队列queueing)服务.在futex.c的注释中,futex起源于"Fast Userspace Mutex&quo ...

  3. phtread&lowbar;mutex 组合

    phtread_mutex通过mutexattr设定其类型,并保存在成员__kind中.pthread_mutex的锁操作函数根据__kind进行方法的分派(dispatch).__kind由5个字段 ...

  4. futex-based pthread&lowbar;cond 源代码分析

    pthread_cond的实现使用了几个futex来协同进行同步,以及如何来实现的. 假定你已经明白 futex,futex-requeue,以及 pthread lowlevellock. < ...

  5. 4&period;1&sol;4&period;2 多线程进阶篇&lt&semi;上&gt&semi;(Pthread &amp&semi; NSThread)

    本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人 “简书” 本文源码 Demo 详见 Githubhttps://github.com/shorfng ...

  6. Windows下使用Dev-C&plus;&plus;开发基于pthread&period;h的多线程程序

    一.下载Windows版本的pthread 目前最新版本是:pthreads-w32-2-9-1-release.zip. 二.解压pthread到指定目录      我选择的目录是:E:\DEV-C ...

  7. NPTL vs PThread

    NPTL vs PThread POSIX threads (pthread) is not an implementation, it is a API specification (a stand ...

  8. Linux pthread

    #include <stdio.h> #include <stdlib.h> #include <string.h> #include <pthread.h& ...

  9. VS2013 配置pthread

    参考:http://blog.csdn.net/qianchenglenger/article/details/16907821 一.下载地址 ftp://sourceware.org/pub/pth ...

随机推荐

  1. 处理大并发之五 使用libevent利器bufferevent

    转自:http://blog.csdn.net/feitianxuxue/article/details/9386843 处理大并发之五 使用libevent利器bufferevent 首先来翻译一段 ...

  2. CSS 分享

    原来的那个暂时不用了,贴出来一下,有兴趣可以参考,原型是Metro,不要禁用css 改了很多次~ 面码大法好!!! /*测试区域*/ /*标题备份*/ h7 { background: #2B6695 ...

  3. Phoenix - Hbase与SQL

    Phoenix - Hbase与SQL 2016-10-23 杜亦舒 Phoenix是什么 简单来说,Phoenix 是一个可以让我们通过SQL的方式操作HBase数据库的框架. HBase是一个No ...

  4. node&period;weiChat

    微信的朋友圈分享是现在流行的推广模式,最近两天尝试了一下使用微信进行商品的分享,分享结束后我可以在自己的数据库中查询到用户是否分享成功,包括用户使用微信进行支付时的成功验证.个人觉得微信上的教程有些绕 ...

  5. 文件搜索神器everything 你不知道的技巧总结

    everything这个软件用了很久,总结了一些大家可能没注意到的技巧,分享给大家 1.指定文件目录搜索示例: TDDOWNLOAD\ abc        在所有TDDOWNLOAD文件夹下搜索包含 ...

  6. java&period;lang&period;IllegalArgumentException&colon; Result Maps collection already contains value for

    如果在SSM整合的时候出现以下的错误: 留意一下是不是既在Mybatis配置文件中加载了映射文件,又在Spring配置文件中使用扫描式去加载映射文件了.两者是不能够重合使用的! Caused by: ...

  7. 解决IOS微信内置浏览器返回后不执行js脚本的问题

    在A页面写一个$(function(){}) 后随便点击一个URL跳转到B页面 利用微信内置浏览器 返回键返回到A页面后发现这段JS不执行,后来找到了解决方案 $(function () { var ...

  8. hive权限配置

    基于CDH5.x的Hive权限配置 1.打开权限控制,默认是没有限制的 set hive.security.authorization.enabled=true; 2.配置默认权限 hive.secu ...

  9. python 基础干货 02

    list 与 tuple list 类似 数组 tuple 跟 list 一样, 只是一旦定义, 里边的内容不可以改变. 这样, 上边的内容就不可以改变了. "可变的" tuple ...

  10. Spring Boot集成Hazelcast实现集群与分布式内存缓存

    Hazelcast是Hazelcast公司开源的一款分布式内存数据库产品,提供弹性可扩展.高性能的分布式内存计算.并通过提供诸如Map,Queue,ExecutorService,Lock和JCach ...