找回密码
 注册
关于网站域名变更的通知
查看: 318|回复: 1
打印 上一主题 下一主题

Linux内核设计与实现之内核同步介绍

[复制链接]

该用户从未签到

跳转到指定楼层
1#
发表于 2020-12-8 15:33 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

EDA365欢迎您登录!

您需要 登录 才可以下载或查看,没有帐号?注册

x
1 t. n$ }4 C! h) T, c; i
存在共享资源(共享一个文件,一块内存等等)的时候,为了防止并发访问时共享资源的数据不一致,引入了同步机制。% A* @: U* s: K9 B0 r. d0 \
4 r- H2 b2 f* k. C, v; Y% e: c
主要内容:
8 M, ^: }+ I7 z: N3 e: C4 R
1 m! _9 A+ s  d6 T: G同步的概念- s& x- q; p; C& i
同步的方法-加锁
/ P( h( A: v! ?0 D3 F( R死锁& E( A, f' }! t! ]) J7 a
锁的粒度2 e( p! Z! w% X7 ^

4 A' e, Z. j4 s9 W% ?  Z% p. S0 r+ E+ o7 ^! U
1. 同步的概念5 n2 l* G; G1 y. d7 H9 U0 F
了解同步之前,先了解另外2个概念:; H3 h* i$ }) v; g$ z
8 X8 {- o* E9 B  l0 N2 e7 R
临界区   - 也称为临界段,就是访问和操作共享数据的代码段。
# C2 H' z( ]$ V5 J竞争条件 - 2个或2个以上线程在临界区里同时执行的时候,就构成了竞争条件。
* `2 R. z! ~5 u- H/ |0 x; @! B ( `6 s' y8 h) v; ^& i/ S$ T8 Q' P
% m  P5 \6 p0 C
所谓同步,其实防止在临界区中形成竞争条件。' X$ J) F. U, W: [; L* Y
$ V2 @& c! s$ w; }' o  W
如果临界区里是原子操作(即整个操作完成前不会被打断),那么自然就不会出竞争条件。
( Z3 F4 y5 @  Z4 p: S% Z# E% \1 C) q" S4 W
但在实际应用中,临界区中的代码往往不会那么简单,所以为了保持同步,引入了锁机制。
2 T" |4 y( s" p5 d! A" b% Q& s
. f" ^# q. g* z5 a  n' |% x
$ b" C' F% k& ~3 U+ q2 Q4 [$ y2 m$ I1 t# Y0 n2 |9 }9 ^
2. 同步的方法-加锁- h2 n) Y3 [: T+ E
为了给临界区加锁,保证临界区数据的同步,首先了解一下内核中哪些情况下会产生并发。
3 J/ L0 r7 |% M
& H& ~1 {4 E: O5 k8 a  ^% m : V, Y! h) R8 X* {

5 v: I2 m% A4 ~" N内核中造成竞争条件的原因:  C8 W/ S. `  g: `( X

2 C. H6 B' e- ]8 T% I竞争原因
2 `7 |- [) U& N" [- s; q7 H5 G) p. Q  k; x& ?2 m0 g- x
说明' n, I8 X* @3 ^3 W6 n! s

. j6 O. E% k/ e$ K中断        中断随时会发生,也就会随时打断当前执行的代码。如果中断和被打断的代码在相同的临界区,就产生了竞争条件3 |% R2 i5 J& t. F( [6 v
软中断和tasklet        软中断和tasklet也会随时被内核唤醒执行,也会像中断一样打断正在执行的代码
4 f; q  P7 i$ N8 Q+ T- |, f内核抢占        内核具有抢占性,发生抢占时,如果抢占的线程和被抢占的线程在相同的临界区,就产生了竞争条件
2 d1 J6 \' d+ t7 }4 M& n睡眠及用户空间的同步        用户进程睡眠后,调度程序会唤醒一个新的用户进程,新的用户进程和睡眠的进程可能在同一个临界区中$ s% Q9 g, p* U4 ?3 a# E$ b
对称多处理        2个或多个处理器可以同时执行相同的代码, I# n# o, z) B2 ^' i
" T/ H: E3 W: M' m
! `% A. f3 N: M$ E9 W% A
为了在编写内核代码时避免出现竞争条件,在编写代码之前就要考虑好临界区在哪,以及怎么加锁。  k$ l7 _9 ]  s* w1 J7 A

# F1 g" u7 G& c' _# W, g5 M在编写完代码后再加锁是非常困难的,很可能还会导致部分代码重写。! i/ \6 s: y7 v) a- c: o* A
1 Q7 h1 Y8 ]" t7 ]# j( ~! v
5 P- A2 V: [2 n, g$ ?

) y' {# V3 J* u5 ]$ `. k$ Y2 q! F" i编写内核代码时,时时记着下面这些问题:
4 a8 s9 N& m+ v) \# [' B, D
  J' ~1 A7 F% h; S5 `这个数据是不是全局的?除了当前线程以外,其他线程能不能访问它?
7 H9 P, e8 G2 j, N+ @这个数据会不会在进程上下文或者中断上下文中共享?它是不是要在两个不同的中断处理程序中共享?
# ?8 z) p1 s4 U! y" J8 V进程在访问数据时可不可能被抢占?被调度的新程序会不会访问同一数据?
' u( O2 ^! q$ L: j( a4 d4 O: x当前进程会不会睡眠(或者阻塞)在某些资源上,如果是,它会让共享数据处于何种状态?
* T, B9 |0 O1 O怎样防止数据失控?7 }' p( t  z$ O0 n) R0 S5 j
如果这个函数又在另一个处理器上被调度将会发生什么?( x) Q1 ?3 |* C2 M3 k- E; F# m. N$ }
2 |, w( l1 P$ |- h6 s& F

4 x' M! E0 M7 t" c; A5 f3. 死锁
8 [) ^- k8 m. K死锁就是所有线程都在相互等待释放资源,导致谁也无法继续执行下去。* W0 Y' d7 b; I7 A& @! h% `
! B% t- l( ^) X7 o& D' z
下面一些简单的规则可以帮助我们避免死锁:
- I% [( m% @& d& i: M) c; K
( }# V  S! v; z4 q3 e如果有多个锁的话,尽量确保每个线程都是按相同的顺序加锁,按加锁相反的顺序解锁。(即加锁a->b->c,解锁c->b->a)
0 U6 Y9 X; m5 B! Y3 ]% B防止发生饥饿。即设置一个超时时间,防止一直等待下去。
" H& C( G4 m$ W; o$ ]不要重复请求同一个锁。
1 g' p5 J  b  z' D! O1 D设计应力求简单。加锁的方案越复杂就越容易出现死锁。7 C3 V- \$ D) ?" o. ?
3 k7 F6 K1 `% o- Z' |
4 M2 h1 ?% o. h/ ^
4. 锁的粒度
9 w$ M3 F. L$ j8 L3 ~在加锁的时候,不仅要避免死锁,还需要考虑加锁的粒度。
4 Q3 H, p, A$ U
8 v: b) o# c6 W锁的粒度对系统的可扩展性有很大影响,在加锁的时候,要考虑一下这个锁是否会被多个线程频繁的争用。8 ?6 _9 n; r, r( t3 p7 p" a

: l! {8 R4 o% a" c( I, r如果锁有可能会被频繁争用,就需要将锁的粒度细化。
1 F6 X( ?7 Z) p  r) M1 b* f4 \4 `
细化后的锁在多处理器的情况下,性能会有所提升。4 z$ X1 a* J8 o. `
3 W& Z( s& w  Y( ]

  A6 [8 K5 b2 I2 y# L3 ~5 q* u& l+ R. w7 }
举个例子说明一下:比如给一个链表加锁,同时有A,B,C 3个线程频繁访问这个链表。
( \+ X$ G7 b  J( d$ Z$ D# {* t: c: g5 r. `
那么当A,B,C 3个线程同时访问这个链表时,如果A获得了锁,那么B,C线程只能等待A释放了锁后才能访问这个链表。
6 |5 @( A8 O( d9 `) f2 q% ?, F1 a- ^% s4 A
. u2 R2 q2 |1 a  E8 D
5 O( t% x  x2 |0 }
如果A,B,C 3个线程访问的是这个链表的不同节点(比如A是修改节点listA,B是删除节点listB,C是追加节点listC),
- C7 F) R% W6 N" j, ?) X+ |. h# q/ n8 t# Z) e4 o  g3 ~
并且这3个节点不是连续的,那么3个线程同时运行是不会有问题的。& \6 w* m2 c. ?5 L$ L

; y; c! I% }  W  l5 |6 @- g, L
7 K3 \! g4 g8 G/ V3 g/ g3 D8 G  g6 L# ]
这种情况下就可以细化这个锁,把加在链表上的锁去掉,改成把锁加在链表的每个节点上。(也就是锁粒度的细化): M. y3 b, s$ k5 a* ?
, a: d4 O; ~/ e) ]! H4 R* k$ H" n
那么,上述的情况下,A,B,C 3个线程就可以同时访问各自的节点,特别是在多处理器的情况下,性能会有显著提高。4 y/ B" t2 E* O% K. o
; ~& q8 M1 o- ]( M

5 \* O, e) v& ?* N5 \
0 J) {; X+ A- ^7 o最后还有一点需要提醒的是,锁的粒度越细,系统开销越大,程序也越复杂,所以对于争用不是很频繁的锁,就没有必要细化了。

该用户从未签到

2#
发表于 2020-12-8 16:20 | 只看该作者
Linux内核设计与实现之内核同步介绍
您需要登录后才可以回帖 登录 | 注册

本版积分规则

关闭

推荐内容上一条 /1 下一条

EDA365公众号

关于我们|手机版|EDA365电子论坛网 ( 粤ICP备18020198号-1 )

GMT+8, 2025-11-24 19:19 , Processed in 0.156250 second(s), 23 queries , Gzip On.

深圳市墨知创新科技有限公司

地址:深圳市南山区科技生态园2栋A座805 电话:19926409050

快速回复 返回顶部 返回列表