1 内核的并发控制
2 linux 内核中竞争发生的情况
3 1. 进程与抢占它的进程
4 2. 进程和中断
5 3. smp 多处理器
6
7 访问共享资源的代码区域一般称之为临界区,
8 临界区需要被以某种互斥的机制加以保护
9
10 上锁
11 临界区
12 解锁
13
14 1.中断屏蔽
15 local_irq_enable(); //使能中断
16 local_irq_disable(); //屏蔽中断
17
18
19 2.原子操作 atomic.h
20 include/asm-generic/atomic.h
21 保护变量
22 类型: atomic_t v
23
24 对于原子操作,所有v操作必须调用其中函数,才能达到原子操作目的
25 atomic_t v = ATOMIC_INIT(0); //初始化v 为0;
26 atomic_read(v) 获取原子操作的值
27
28 static inline void atomic_add(int i, atomic_t *v)
29 把原子操作v 加上i
30
31 static inline void atomic_sub(int i, atomic_t *v)
32 v 减 i
33
34 static inline void atomic_inc(atomic_t *v) 自增
35 static inline void atomic_dec(atomic_t *v) 自减
36
37 atomic_dec_and_test 自减 和 0比较
38
39 3.自旋锁
40 spinlock.h
41 当获取不了资源时候,CPU会在原地打转
42 spinlock_t lock定义自旋锁
43 spin_lock_init(&lock) 自旋锁的初始化
44 spin_lock(&lock) 上锁
45
46 spin_unlock(&lock) 解锁
47
48 spin_trylock(&lock) 该函数立即返回
49 如果获取成功返回非0 失败返回0
50
51
52
53 读写自旋锁 rwlock.h
54 当访问一块共享区域,读的操作并不会影响到共享区域,所以读和读之间没有必要互斥
55
56 读和读 不互斥
57 写和写 互斥
58 读和写 互斥
59
60 前提: 临界区 一定要严格区分 读和写
61
62 rwlock_t 读写自旋锁的类型
63
64 rwlock_init(&lock) 初始化
65
66 读
67 read_lock(&lock) 上读锁
68 read_unlock(&lock) 解读锁
69
70 写
71 write_lock(&lock) 上写锁
72 write_unlock(&lock) 解写锁
73
74 读锁和写锁 必须指向同一个 lock
75
76 顺序锁
77 seqlock_t 类型
78 针对 读写锁一个改进,在读写锁基础上,让读和写 不再互斥
79 这种锁 适用如下场景:
80 1.能够严格区分 读 和 写
81 2. 读的操作要远大于写操作,反之有可能会造成死锁
82
83 seqlock_init(&lock); 读写的初始化
84
85 write_seqlock(&lock) 上写锁
86 xxxxx
87 write_unseqlock(&lock) 解写锁
88
89
90 读锁
91 read_seqbegin();
92 read_seqretry();
93 do {
94 seq = read_seqbegin(&lock);
95 xxxxxx; 临界区
96 }while(read_seqretry(&lock, seq))
97
98
99
100
101 4.信号量
102 semaphore.h
103 信号量会引发进程间的调度
104
105 semaphore ;
106 sema_init(&sema, 1); //初始化为1 用于互斥
107
108 down(&sem) 获取信号量
109 down_trylock(&sema); 立即返回,无论有没有获得锁,
110
111 up(&sem) 释放信号量
112
113
114 读写信号量 同读写自旋锁
115 rwsem.h
116 rw_semaphore 类型
117 init_rwsem(&rwsem) 初始化
118
119 down_read(&rwsem) 上读锁
120 up_read(&rwsem) 解读锁
121
122 down_write(&rwsem) 上写锁
123 up_write(&rwsem) 解写锁
124
125 总结:
126 1.关闭中断尽量不要用
127 2.原子操作针对是变量,自旋锁和信号量保护代码段
128 3.由于信号量会引发进程间的调度,进程间切换是需要消耗事件,
129 所以如果保护代码段比较小,适合用自旋锁,如果保护的代码段比较大,
130 适合用信号量.
131 4.自旋锁是忙等,不会引发进程的切换,如果中断需要互斥,用spinlock
132 spinlock_trylock
133 5.会引起阻塞的代码段,不要用spinlock,用信号量
134
135
136 互斥体
137 简化版的信号量 信号量值为1,简化版
138
139 mutex
140
141 mutex_init(&mutex) //初始化信号量
142 mutex_lock(&mutex) 上锁
143 mutex_unlock(&mutex) 解锁