linux 内核的futex - requeue 以及 requeue-pi
futex为更好支持pthread_cond的实现(,最主要是broadcast),设计了requeue功能,并以futex系统调用提供操作接口,包括一对配对的操作 futex_wait_requeue_pi 以及 futex_requeue。
mutex互斥体,确保临界区之间互斥(mutual exclusion),但不能满足不同临界区之间的前驱后继的关系,所以可以通过在临界区A使用condition variable条件变量,等待另一临界区B的发出信号指令。
Condition Variables
Synchronization mechanisms need more than just mutual exclusion; also need a way to wait for another thread to do something.
临界区A,与临界区B虽然使用了mutex,确保彼此之间互斥(mutual exclusion)。但是同时使用了condvar,保证临界区B前驱,临界区A后继,即临界区A等待临界区B先完成某些事。
一个condvar必须从属于(belong to)一个mutex。
因此condvar的等待(wait)包含了两次等待,或两个队列等待。一个是condvar信号的等待(队列),另一个是它所属的mutex锁的等待(队列)。这使得一次condvar wait必须先释放mutex,然后依次等待condvar信号和mutex。这意味着等待的线程必须进行两次等待和两次唤醒。
对condvar发起信号signal,就是唤醒其中一个等待在condvar的线程,让它转而等待condvar所属的mutex,再次回到临界区执行。而broadcast最简单的方法就是将所在等待在condvar的线程统统唤醒。
当对condvar进行broadcast时,多个等待在condvar的线程被唤醒回到用户空间,一起去竞争condvar所属的mutex,而又每个线程又因锁竞争必须再次回到内核进行排队等待,从而造成了多次的线程切换,系统调用的浪费。
为了改善这种浪费,可以将一个等待在两个等待队列之间的转换,优化在一次调用中进行,避免多个线程被唤醒去竞争锁。这样的功能就是futex提供的requeue。
被requeue后的waiter(,调用futex_wait_requeue_pi而阻塞的线程),必须等待condvar所属的mutex去唤醒。当waiter从futex_wait_requeue_pi系统调用阻塞中被唤醒,并不表示已经获得了condvar所属的mutex锁,而是要去竞争这个锁。
requeue将这个过程的condvar和mutex看作为futex1和futex2。
futex_requeue函数原型为
static int futex_requeue(u32 __user *uaddr1, unsigned int flags, u32 __user *uaddr2, int nr_wake, int nr_requeue, u32 *cmpval, int requeue_pi);
这个函数的功能是,将uaddr1对应的futex等待队列出队最多 (nr_wake + nr_requeue) 个futex_q,先对出队的futex_q进行唤醒nr_wake个,剩下的才进行requeue到futex2等待队列。而pthread_cond_broadcast固定设定参数 nr_wake = 1,nr_requeue = INT_MAX。就是说在broadcast的时候只会唤醒一个线程去竞争futex2,其余阻塞在futex1的线程都会出队再入队到futex2的等待队列。
requeue-pi 就是condvar所属的mutex是一个使用pi协议的mutex,即futex2是pi-futex,requeue对一个non-pi futex的waiters出队再入队到pi-futex等待队列进行特殊的优化。futex_requeue函数只会将可以马上获得pi-futex锁的线程唤醒,也就是说对每一个requeue到pi-futex的waiter都先尝试锁pi-futex,尝试成功的才能被唤醒,直到有线程被唤醒,其余waiter就直接requeue到pi-futex,而不再进行锁尝试。虽然futex_proxy_trylock_atomic并不像futex_lock_pi那样会去调用rt_mutex_trylock,但是与non-pi到non-pi的requeue,增加了额外的尝试。
下面是requeue non-pi 和 requeue-pi 分支的逻辑对比:
linux 内核的futex - requeue 以及 requeue-pi的更多相关文章
- linux 内核的futex pi-support,即pi-futex使用rt_mutex委托
futex的pi-support,也就是为futex添加pi算法解决优先级逆转的能力,使用pi-support的futex又称为pi-futex.在linux内核的同步机制中,有一个pi算法的成例,就 ...
- linux 内核的futex
futex是linux内核为用户空间实现锁等同步机制而设计的同步排队(队列queueing)服务.在futex.c的注释中,futex起源于"Fast Userspace Mutex&quo ...
- linux 内核的各种futex
futex 设计成用户空间快速锁操作,由用户空间实现fastpath,以及内核提供锁竞争排队仲裁服务,由用户空间使用futex系统调用来实现slowpath.futex系统调用提供了三种配对的调用接口 ...
- linux内核级同步机制--futex
在面试中关于多线程同步,你必须要思考的问题 一文中,我们知道glibc的pthread_cond_timedwait底层是用linux futex机制实现的. 理想的同步机制应该是没有锁冲突时在用户态 ...
- Linux内核--网络栈实现分析(十一)--驱动程序层(下)
本文分析基于Linux Kernel 1.2.13 原创作品,转载请标明http://blog.csdn.net/yming0221/article/details/7555870 更多请查看专栏,地 ...
- linux内核数据结构学习总结
目录 . 进程相关数据结构 ) struct task_struct ) struct cred ) struct pid_link ) struct pid ) struct signal_stru ...
- Linux内核之内存管理完全剖析
linux虚拟内存管理功能 ? 大地址空间:? 进程保护:? 内存映射:? 公平的物理内存分配:? 共享虚拟内存.实现结构剖析 (1)内存映射模块(mmap):负责把磁盘文件的逻辑地址映射到虚拟地 ...
- Linux内核中流量控制
linux内核中提供了流量控制的相关处理功能,相关代码在net/sched目录下:而应用层上的控制是通过iproute2软件包中的tc来实现, tc和sched的关系就好象iptables和netfi ...
- Linux内核数据包的发送传输
本文主要讲解了Linux内核数据包的传输流程,使用的内核的版本是2.6.32.27 为了方便理解,本文采用整体流程图加伪代码的方式从内核高层面上梳理了二层数据包发送传输的流程,希望可以对大家有所帮助. ...
随机推荐
- JVM中堆内存和栈内存的区别
Java把内存分成两种,一种叫做栈内存,一种叫做堆内存 在函数中定义的一些基本类型的变量和对象的引用变量都是在函数的栈内存中分配.当在一段代码块中定义一个变量时,java就在栈中为这个变量分配内存空间 ...
- JS和Flash(AS)相互调用
<!DOCTYPE html> <html> <head> <title>swf</title> <meta charset=&quo ...
- WKWebView代理方法解析
一.前言 上一篇文章已经对WKWebView做了一个简单的介绍,主要对它的一些方法和属性做了一个简单的介绍,今天看一下WKWebView的两个协议:WKNavigationDelegate 和 WKU ...
- Win10 Bash/WSL调试Linux环境下的.NET Core应用程序
一.简介 使用过Mac OS的程序员都知道,在Mac Book Pro上写程序是一件比较爽的事儿,作为dotneter,我们都比较羡慕Mac系统的环境,比如命令行,当然设备也是挺漂亮的. 在新的Win ...
- java做帐户登录失败锁定
对于连续失败登录应用系统5次的帐号,需锁定该帐号至少30分钟不允许登录. 这里也用简单的map集合进行判定,功能能实现,但并不是很完美,不用更改数据库的表字段 1.首先建立一个用户登陆失败的实体类 p ...
- Apache优化
控制MaxClients的设置,以避免服务器产生太多的子进程而发生交换.进程间的数据交换会占用很大内存,数据交换产生的滞后使用户总感觉"不够快",所以用户就可能去按"停止 ...
- Luogu3373【模板】线段树2
P3373[模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格式: 第一行 ...
- 【Electron】Electron开发入门(二):创建项目Hello Word
创建简单的Electron程序 1.首先,切换到你的项目空间,我的在 D:\ProjectsSpace\ElectronProjects\ElectronTest,ElectronTest是案例项目文 ...
- hive 锁表问题
报错如下: Unable to acquire IMPLICIT, EXCLUSIVE lock dms@pc_user_msg@month=201611 after 100 attempts. 显示 ...
- 在hive中直接对timestamp类型取max报错
之前直接对timestamp类型做max操作, select id,max(updatetime) updatetime from his.tag group by id; 结果查询的结果有的显示为1 ...