阅读笔记-个人记录
7.1并发和竞态
并发 :多个执行单元同时、并行被执行,而并发的执行单元对共享组员的访问很容易导致竞态
竞态发生情况:
1.对称多处理器(SMP)的多个CPU
2.单CPU内进程与抢占它的进程
一个进程在内核执行的时候可能耗完了自己的时间片,也可能被另一个高优先级进程打断,而进程与抢占它的进程访问共享资源的情况
3.中断与进程之间
中断可以打断正在执行的进程,且此时中断服务程序访问进程正在访问的资源,竞态也会发生;中断也有可能被更高优先级中断打断。
解决:保证对共享资源的互斥访问。即一个执行单元在访问共享资源时,其他执行单元被禁止访问
访问共享资源额代码区域成为临界区,需要某种互斥机制加以保护
7.2编译乱序和执行乱序
编译乱序:编译顺序不按照源代码中的顺序 解决:barrier()编译屏障“_asm__volatile_("":::"memory")”
执行乱序:
7.3 中断屏蔽
在进入临界区前屏蔽系统的中断,底层就是让CPU本身不响应中断。
7.4原子操作
7.5自旋锁
需先执行一个原子操作,该操作测试并设置某个内存变量,简单理解:把自旋锁当做一个变量看待,该变量把一个临界区标记为“我当前在运行,请稍等一会”或者是“我当前不在运行,可被使用”
Linux自旋锁常用操作4种:
(1)定义自旋锁
spinlock_t lock;
(2)初始化
spin_lock_init(lock);
(3) 获得自旋锁
spin_lock(lock);
(4)释放自旋锁
spin_unlock(lock);
主要针对SMP或单CPU但内核可抢占的情况。
自旋锁可以保证临界区不受别的CPU和本CPU内的抢占进程打扰,但在得到锁的代码路径在执行临界区的时候还可能受到中断和底半部的影响,就需要自旋锁的衍生。
驱动工程师应谨慎使用自旋锁,可能造成一下几个问题:
<1>当临界区很大,需要较长时间占用锁,使用自旋锁会降低系统的性能
<2>可能导致死锁
<3>锁定期间不能调用可能引起进程调度的函数
<4>单核编程的时候应认为自己的CPU是多核的
读写自旋锁 读操作可以并发 写操作只能同时有一个执行单元 读写不能同时进行
顺序锁 对读写锁的优化 读执行单元不会被写执行单元阻塞,读写不互斥 但写执行单元之间仍然是互斥的。
RCU锁机制 读-复制-更新
7.6信号量 semaphore
值可以为0,1,n (PV操作)
P(S):(1)信号量S减一 S=S-1
(2) if S>=0 进程继续 else 进程进入等待队列
V(S): (1)S=S+1
(2)if S>0 唤醒等待队列中的信号量
7.7互斥体 mutex
互斥体是进程级的,用于多个进程之间对资源的互斥
7.8完成量
用于一个执行单元等待另一个执行单元执行完某事