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 , 并发 , 自旋锁
© 除非另有注明本文采用知识共享署名-非商业性使用-相同方式共享 2.5 中国大陆许可协议进行许可。
© 你可以发表评论,并在保留原文地址及作者的情况下引用到你的网站或博客。
© 转载请注明: LDD读书笔记第五章-并发和竞态(二) | 转自: Senghoo's Blog
© Tag: ldd , 并发 , 自旋锁