LDD读书笔记第五章-并发和竞态(二)

锁陷阱

不明确的规则:每个线程不能第二次尝试获得该锁。
锁的顺序规则:保证每个线程都以相同的顺序获得锁。
锁的粒度对比:粗粒度锁会导致竞争严重,细粒度锁会导致额外的开销和给维造成副作用

除了锁之外的方法

免锁算法

大量的读取者,只有一个写入者可以使用免锁算法。
免锁算法类似于循环队列(个人理解)。

原子变量

原子变量执行速度非常块。
只要有可能编译器会把对原子变量的操作编译成单条指令。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*头文件和相关初始化*/
#include <asm/atomic.h>
atomic_t v = ATOMIC_INIT(value);
void atomic_set(atomic_t *v, int i);
/*读取,加减,自增,自减*/
int atomic_read(atomic_t *v);
void atomic_add(int i, atomic_t *v);
void atomic_sub(int i, atomic_t *v);
void atomic_inc(atomic_t *v);
void atomic_dec(atomic_t *v);
/*和上面的函数功能相同,但是会测试,如果结果为0返回真其他情况返回假*/
int atomic_inc_and_test(atomic_t *v);
int atomic_dec_and_test(atomic_t *v);
int atomic_sub_and_test(int i, atomic_t *v);
/*将i累加到v,结果为负返回真其他返回假*/
int atomic_add_negative(int i, atomic_t *v);
/*和上面函数相同,区别是返回结果。*/
int atomic_add_return(int i, atomic_t *v);
int atomic_sub_return(int i, atomic_t *v);
int atomic_inc_return(atomic_t *v);
int atomic_dec_return(atomic_t *v);

位操作

1
2
3
4
5
6
7
8
9
/*设置,清除,修改,返回*/
void set_bit(nr, void *addr);
void clear_bit(nr, void *addr);
void change_bit(nr, void *addr);
test_bit(nr, void *addr);
/*和上面相同,区别于会返回先前值*/
int test_and_set_bit(nr, void *addr);
int test_and_clear_bit(nr, void *addr);
int test_and_change_bit(nr, void *addr);

seqlock

频繁发生访问但很少发生写入且必须快速访问时使用seqlock。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <linux/seqlock.h>
seqlock_t lock = SEQLOCK_UNLOCKED;
seqlock_init(seqlock_t *lock);
unsigned int read_seqbegin(seqlock_t *lock);
unsigned int read_seqbegin_irqsave(seqlock_t *lock, unsigned long flags);
int read_seqretry(seqlock_t *lock, unsigned int seq);
int read_seqretry_irqrestore(seqlock_t *lock, unsigned int seq, unsigned long flags);
void write_seqlock(seqlock_t *lock);
void write_seqlock_irqsave(seqlock_t *lock, unsigned long flags);
void write_seqlock_irq(seqlock_t *lock);
void write_seqlock_bh(seqlock_t *lock);
int write_tryseqlock(seqlock_t *lock);
void write_sequnlock(seqlock_t *lock);
void write_sequnlock_irqrestore(seqlock_t *lock, unsigned long flags);
void write_sequnlock_irq(seqlock_t *lock);
void write_sequnlock_bh(seqlock_t *lock);

列:

1
2
3
4
5
unsigned int seq;
do {
seq = read_seqbegin(&the_lock);
	操作。。。。;
} while read_seqretry(&the_lock, seq);

读取-复制-更新(RCU)

1
2
3
4
#include <linux/rcupdate.h>
void rcu_read_lock;
void rcu_read_unlock;
void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg);

对锁的一点理解

对于单CPU非抢占式内核,锁机制仅仅是空语句,除非线程主动放弃CPU,不会发生调度,所以操作是安全的。
对于单CPU抢占式内核,锁机制仅会关闭抢占,从而情况和单CPU非抢占差不多,但是在退出临界区以后要开启抢占
对于多CPU的情况,锁机制才能完全发挥功能。一个CPU(1)进入临界区禁用抢占(该CPU)开始处理数据。其他CPU(2)证号也要访问相同的数据。
这时候开始自旋等待CPU(1)释放锁。

----------------- 全文结束 -----------------
© 该日志作者:Senghoo, 于2010年07月16日发表于分类"Linux Kernel"下;
© 除非另有注明本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
© 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
© 转载请注明: LDD读书笔记第五章-并发和竞态(二) | 转自: Senghoo's Blog
© Tag: , ,

你可以继续围观

  • LDD读书笔记第五章-并发和竞态(一)
    linux信号量的实现 #include /*信号量相关头文件*/ struct semaphore /*信号量相关结构体*/ /*初始化相关函数*/ void sema_init(struct semaphore *sem,int val); /*初始化信号量函数*/ D...
  • LDD读书笔记第七章-时间、延迟及延缓操作
    度量时间差 在linux/param.h中定义HZ值,表示每秒发生时钟中断的频率。 内核时钟计数器:jiffies_64。 内核使用jiffies变量是unsigned log类型。 可能是jiffies_64的值也可能是其底32位。 使用jiffies计数器 头文件:linux/jif...

发表评论