Nginx原子操作及自旋锁实现
Nginx原子操作
执行原子操作的变量只有整形
这两种整型都使用了volatile关键字告诉C编译器不要做优化
nginx原子操作提供的2个方法
ngx_atomic_cmp_set
入参:ngx_auomic_t*lock,ngx_atomic_unit_t old,ngx_atomic_unit set
compare & set
ngx_atomic_fetch_add
入参:ngx_atomic_t*value,ngx_atomic_int_t add
x86的SMP多核架构下的原子操作
当无法实现原子操作时就只能用volatile 关键字在C语言级别上模拟原子操作目前绝大多数体系架构都是支持原子操作的
Nginx在源代码中实现对整型的原子操作需通过内联汇编语言直接操作硬件才能做到
使用GCC编译器在C语言中嵌入汇编语言的方式使用__asm__关键字
__asm__volatile(汇编语句部分):输出部分:输入部分:破坏描述部分
volatile关键字用于限制GCC编译器对这段代码做优化
GCC如何内联汇编语言
汇编语句
引号中所包含的汇编语句可以直接用占位符%来引用C语言中的变量 (最多10个,%0~%9)
介绍个汇编语句
cmpxchgl r,[m]
首先会用m比较eax寄存器中的值如果相等 则把m的值设为r,zf标志位设为1否则将zf标志位设为0,寄存器中的值设为m
输出部分
将寄存器中的值设置为C语言变量中
输入部分
将C语言变量设置到寄存器中
破坏描述部分
通知编译器使用了哪些寄存器、内存
ngx_atomic_cmp_set
从内存中获取lock变量(不使用寄存器)把old变量写入eax寄存器把set变量写入通用寄存器
首先锁住总线防止多核的并发执行接着判断原子变量old和old值是否相等若相等 则把lock值设为set 同时res为1若不相等 则设res为0
自旋锁
每当内核调度到这个进程执行时就持续检查是否可以获得到锁在拿不到锁时这个进程的代码将会一直在自旋锁代码处执行直到其他进程释放了锁且当前进程获得到锁代码才会继续向下执行
适用场景
自旋锁主要为多处理器操作系统而设置解决的共享资源保护场景是进程使用锁的时间非常短(如果太久 会占用大量的CPU资源)
如果使用锁的进程不希望自己进入睡眠状态特别它处理的是非常核心的事件时这时应该使用自旋锁大部分情况下Nginx的worker进程最好都不要进入睡眠状态因为它非常繁忙这个进程的epoll上可能会有十万甚至百万的TCP连接等待着处理进程一旦睡眠后必须等待其他时间的唤醒这中间极其频繁的进程间切换带来的负载消耗可能无法让用户接受
注意
自选锁对于单处理器操作系统来说一样有效不进入睡眠状态并不意味着其他可执行状态的进程得不到执行Linux内核中对于每个处理器都有一个运行队列自选锁可以仅仅调整当前进程在运行队列中的顺序或者调整进程的时间片这都会为当前处理器上的其他进程提供被调度的机会以使得锁被其他进程释放
Nginx基于原子操作的自旋锁ngx_spinlock的实现
入参:
a、
lock是原子变量表达的锁值为0表示锁是被释放的值不为0表示锁已经被某个进程持有了
b、value参数表示希望当锁没有被任何进程持有时(也就是lock值为0)把lock值设为value表示当前进程持有了
c、spin参数表示在多处理器系统内当ngx_spinlock方法没有拿到锁时当前进程在内核的一次调度中该方法等待其他处理器释放锁的时间
ngx_spinlock实现逻辑
不要立刻让出CPU
在多处理器下更好的做法是当前进程不要立刻让出正在使用的CPU处理器而是等待一段时间看看其他处理器上的进程是否会释放锁这会减少进程间切换的次数
检查lock是否释放的频率越来越小
随着等待的次数越来越多实际去检查lock是否释放的频率会越来越小因为检查lock值会更消耗CPU而执行ngx_cpu_pause对于CPU能耗很节省的
nginx_cpu_pause
nginx_cpu_pause是在许多架构体系中专门为了自选锁而提供的命令它会告诉CPU现在处于自选锁等待状态通常一些CPU会将自己置于节能状态 降低功耗"注意"在执行ngx_cpu_pause后当前进程没有让出正使用的处理器
ngx_sched_yield
当前进程仍然处于可执行状态但暂时让出处理器使得处理器优先调度其他可执行状态的进程在进程被内核再次调度时 在for循环代码中可以期望其他进程释放锁
Nginx原子操作及自旋锁实现相关推荐
- Nginx学习之四-Nginx进程同步方式-自旋锁(spinlock)
自旋锁简介 Nginx框架使用了三种消息传递方式:共享内存.套接字.信号. Nginx主要使用了三种同步方式:原子操作.信号量.文件锁. 基于原子操作,nginx实现了一个自旋锁.自旋锁是一种非睡眠锁 ...
- Linux并发与竞争介绍(原子操作、自旋锁、信号量、互斥体)
目录 并发与竞争 并发与竞争简介 保护内容是什么 原子操作 原子操作简介 原子整形操作API函数(atomic_t 结构体) 原子位操作API 函数 自旋锁 自旋锁简介 自旋锁API函数 线程与线程 ...
- 大话Linux内核中锁机制之原子操作、自旋锁【转】
转自:http://blog.sina.com.cn/s/blog_6d7fa49b01014q7p.html 多人会问这样的问题,Linux内核中提供了各式各样的同步锁机制到底有何作用?追根到底其实 ...
- linux 内核同步--理解原子操作、自旋锁、信号量(可睡眠)、读写锁、RCU锁、PER_CPU变量、内存屏障
内核同步 内核中可能造成并发的原因: 中断–中断几乎可以在任何时刻异步发生,也就可以随时打断当前正在执行的代码. 软中断和tasklet–内核能在任何时刻唤醒或调度软中断和tasklet,打断当前正在 ...
- Linux内核的并发与竞态、信号量、互斥锁、自旋锁
/************************************************************************************ *本文为个人学习记录,如有错 ...
- 漫画Linux 并发、竞态、互斥锁、自旋锁、信号量
1. 锁的由来? 学习linux的时候,肯定会遇到各种和锁相关的知识,有时候自己学好了一点,感觉半桶水的自己已经可以华山论剑了,又突然冒出一个新的知识点,我看到新知识点的时候,有时间也是一脸的懵逼,在 ...
- 漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?
文章目录 1. 锁的由来? 2. 什么是并发和竞态? 2.1 并发与竞态概念 3. 讨论下死锁 3.1 多进程调度导致死锁 3.2 单线程导致死锁 4. 互斥锁和自旋锁.信号量的区别? 5. 如何解决 ...
- linux 信号量 自旋锁 测试 实验,「正点原子Linux连载」第四十八章Linux并发与竞争实验...
1)实验平台:正点原子Linux开发板 2)摘自<正点原子I.MX6U嵌入式Linux驱动开发指南> 关注官方微信号公众号,获取更多资料:正点原子 第四十八章Linux并发与竞争实验 在上 ...
- Linux C/C++ 并发下的技术方案(互斥锁、自旋锁、原子操作)
前言 线程:是操作系统能够进行运算调度的最小单位.它被包含在进程之中,是进程中的实际运作单位.一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务.在Uni ...
最新文章
- Away3d 骨骼动画优化
- Raspberry Pi 4B 部署 YOLOX
- ASP.NET Web Pages 的冲突版本问题
- 如何 给给软件开发 添加 代理_敏捷开发是如何被跑偏的
- (转)shiro权限框架详解06-shiro与web项目整合(下)
- 如何有效的保护计算机,如何保护计算机-20210717095143.pdf-原创力文档
- 二、python_base
- js中,还真不了解 console
- ECharts - dataset组件的用法详解
- 【集合论】关系闭包 ( 自反闭包 | 对称闭包 | 传递闭包 )
- Oracle之同义词
- 【NLP】第13章 用Transformers分析假新闻
- 【产品经理】产品经理进阶之路(六):互联网思维详解
- 月之暗面(树形dp)
- 特征值和奇异值的关系
- Android:高德SDK的基本使用
- 003 Rust 网络编程,使用 IpAddr
- UML时序图画法简介-sequenceDiagram
- mmwave studio使用
- 达内C++21天培训视频教程
热门文章
- mybatis Table book.t_abmin not find
- listdir在python3_Python3 os.listdir() 方法
- 云栖社区,诚邀技术同仁一同入驻
- JVM调优(二)垃圾回收算法
- Android屏幕禁止休眠的方法
- LeetCode:Rotate Image
- Quartz框架应用(1)
- mysql5.5和5.6版本间的坑
- css3---( 框架)
- Windows Mobile 7(Photon) 梦幻之旅系列-前言