可以了解并学习Linux 内核的同步机制.doc

上传人:白大夫 文档编号:3399867 上传时间:2019-08-21 格式:DOC 页数:12 大小:46.50KB
返回 下载 相关 举报
可以了解并学习Linux 内核的同步机制.doc_第1页
第1页 / 共12页
亲,该文档总共12页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

《可以了解并学习Linux 内核的同步机制.doc》由会员分享,可在线阅读,更多相关《可以了解并学习Linux 内核的同步机制.doc(12页珍藏版)》请在三一文库上搜索。

1、可以了解并学习Linux 内核的同步机制Linux内核同步机制,挺复杂的一个东西,常用的有自旋锁,信号量,互斥体,原子操作,顺序锁,RCU,内存屏障等。这里就说说它们的特点和基本用法。自旋锁 :通用的 和读写的特点:1. 处理的时间很短。2. 尝试获取锁时,不能睡眠,但是有trylock接口可以直接退出。3. 多用在中断中。4. 任何时候只有一个保持者能够访问临界区。5. 可以被中断打断的(硬件和软件的)6. 获取自旋锁后首先就是关闭了抢占spin_lock使用接口:C1234567891011121314151617 void spin_lock_init(spinlock_t *lock)

2、; /initvoid spin_lock(spinlock_t *lock); / 获取锁void spin_unlock(spinlock_t *lock); /释放锁其他变体typedef struct spinlock union struct raw_spinlock rlock;#ifdef CONFIG_DEBUG_LOCK_ALLOC# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map)struct u8 _paddingLOCK_PADSIZE;struct lockdep_map dep_map;#endi

3、f; spinlock_t;Rwlock: 读写自旋锁基本特点和通用自旋锁一样,但是有时候多线程频繁读取临界区如果同时只能一个那么效率会很低,它的特点就是在读的时候获取读锁,可以同时有N个线程同时读,在写时需要获得写锁(不能有读和写锁)。在读操作时,写操作必须等待;写操作时,读操作也需要的等待。这样虽然避免了数据的不一致,但是某些操作要等待,后面还会出现顺序锁,是对读写锁的优化,把写的优先级调高了使用接口:C1234567891011121314151617181920212223242526rwlock_init(lock); /initread_lock(lock); /获取读锁read_

4、unlock(lock) ;write_lock (lock); /获取写锁write_unlock(lock);/* include/linux/rwlock_types.h - generic rwlock type definitions* and iniTIalizers* porTIons Copyright 2005, Red Hat, Inc., Ingo Molnar* Released under the General Public License (GPL)。*/typedef struct arch_rwlock_t raw_lock;#ifdef CONFIG_GEN

5、ERIC_LOCKBREAKunsigned int break_lock;#endif#ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner;#endif#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;#endif rwlock_t;而关于自旋锁的缺点?这里找到ibm一个文章信号量(semaphore):通用的 和读写的相对于自旋锁,它最大的特点就是允许调用它的线程进入睡眠C123456/* Please dont access any mem

6、bers of this structure directly */struct semaphore raw_spinlock_t lock;unsigned int count;struct list_head wait_list;void sema_init(struct semaphore *sem, int val); / val值代表了同时多少个线程可以进入临界区,一般为1 即作为互斥体使用;当然1 时,并发操作同一资源会引发什么呢?down_interrupTIble(struct semaphore *sem); / 获取信号量 ,它是可以中断的。up(struct semaph

7、ore *sem); / 释放信号量,一般配对使用,当然也可以在别的线程里释放它。读写信号量:rwsem 它和读写自旋锁类似 除了线程可以睡眠C1234567891011121314151617181920/* the rw-semaphore definiTIon* - if activity is 0 then there are no active readers or writers* - if activity is +ve then that is the number of active readers* - if activity is -1 then there is one

8、 active writer* - if wait_list is not empty, then there are processes waiting for the semaphore*/struct rw_semaphore _s32 activity;raw_spinlock_t wait_lock;struct list_head wait_list;#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;#endif;init_rwsem(sem) ; / 初始化down_read(struct rw_semaphore

9、*sem); / 获取读信号量up_read(struct rw_semaphore *sem); /释放读信号量down_write(struct rw_semaphore *sem); /获取写信号量up_write(struct rw_semaphore *sem); / 释放写信号量互斥体(mutex):和count=1的信号量几乎没有区别,当然拥有互斥锁的进程总是尽可能的在短时间内释放C1234567891011121314151617181920struct mutex /* 1: unlocked, 0: locked, negative: locked, possible wa

10、iters */atomic_t count;spinlock_t wait_lock;struct list_head wait_list;#if defined(CONFIG_DEBUG_MUTEXES) | defined(CONFIG_SMP)struct task_struct *owner;#endif#ifdef CONFIG_DEBUG_MUTEXESconst char *name;void *magic;#endif#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;#endif;mutex_init(mutex

11、); / init 互斥锁mutex_lock(); /获取互斥锁,几乎都能获取mutex_unlock(); /释放互斥锁原子操作(atomic)(和架构相关,就是多条指令相当于一条指令执行,多用于计数)组要是在smp上有意义,防止多条指令被多cpu执行。也是为了实现互斥。顺序锁(sequence)特点:和读写自旋锁锁类似,但是它的写不会等待。写的时候持有自旋锁。首先读者的代码应该尽可能短且写者不能频繁获得锁,其次被保护的数据结构不包括被写修改的指针或被读间接引用的指针。当要保护的资源很小很简单,会很频繁被访问并且写入操作很少发生且必须快速时,就可以用seqlock。C12345678910

12、111213141516171819202122232425Seqlock:typedef struct unsigned sequence;spinlock_t lock; seqlock_t;seqlock_init(x) / DEFINE_SEQLOCK(x) / initwrite_seqlock(seqlock_t *sl) ; / 获取写锁write_sequnlock(seqlock_t *sl);read_seqbegin 和 read_seqretry 结合使用 /读时如果有写锁,则循环等待直到锁释放。应用实例drivers/md/md.cretry:seq = read_s

13、eqbegin(memset(bbp, 0xff, PAGE_SIZE);for (i = 0 ; i bb-count ; i+) u64 internal_bb = pi;u64 store_bb = (BB_OFFSET(internal_bb) 10)| BB_LEN(internal_bb);bbpi = cpu_to_le64(store_bb);bb-changed = 0;if (read_seqretry(RCU:read-copy-update在linux提供的所有内核互斥设施当中属于一种免锁机制。Rcu无需考虑读和写的互斥问题。它实际上是rwlock的一种优化。读取者不必

14、关心写入者。所以RCU可以让多个读取者与写入者同时工作。写入者的操作比例在10%以上,需要考虑其他互斥方法。并且必须要以指针的方式来访问被保护资源。Rcu_read_lock /仅仅是关闭抢占Rcu_read_unlock /打开抢占Rcu_assign_pointer(ptr,new_ptr)/等待队列:它并不是一种互斥机制。它辅助comletion。/它主要用来实现进程的睡眠等待。/操作接口:wait/ wake_upC12345struct _wait_queue_head spinlock_t lock;struct list_head task_list;typedef struct

15、 _wait_queue_head wait_queue_head_t;完成接口(completion) :该机制被用来在多个执行路径间作同步使用,即协调多个执行路径的执行顺序。如果没有完成体,则睡眠在wait_list上。这里usb 在提交urb时会用到。如果驱动程序要在执行后面操作之前等待某个过程的完成,它可以调用wait_for_completion,以要完成的事件为参数:Completion机制是线程间通信的一种轻量级机制:允许一个线程告诉另一个线程工作已经完成C123456789101112struct completion unsigned int done;wait_queue_

16、head_t wait;接口:DECLARE_COMPLETION(x) / 静态定义completioninit_completion(struct completion *x); / 动态initINIT_COMPLETION(x); / 初始化一个已经使用过的completionWait_for_completion(struct completion *x);complete(struct completion *); /done +1,唤醒等待的一个。Complete_all / 唤醒所有的,一般不会用。内存屏障内存屏障主要有:读屏障、写屏障、通用屏障、优化屏障内存屏障主要解决了两个

17、问题:单处理器下的乱序问题和多处理器下的内存同步问题编译器优化以保证程序上下文因果关系为前提。以 读屏障为例,它用于保证读操作有序。屏障之前的读操作一定会先于屏障之后的读操作完成,写操作不受影响,同属于屏障的某一侧的读操作也不受影响。类似的, 写屏障用于限制写操作。而通用屏障则对读写操作都有作用。而优化屏障则用于限制编译器的指令重排,不区分读写。前三种屏障都隐含了优化屏障的功能。比如:tmp = ttt; *addr = 5; mb(); val = *data;有了内存屏障就了确保先设置地址端口,再读数据端口。而至于设置地址端口与tmp的赋值孰先孰后,屏障则不做干预。有了内存屏障,就可以在隐

18、式因果关系的场景中,保证因果关系逻辑正确。在Linux中,优化屏障就是barrier()宏,它展开为asm volatile(“”:”memory”)smp_rmb(); / 读屏障smp_wmb(); /写屏障smp_mb(); / 通用屏障Blk:大内核锁BKL(大内核锁)是一个全局自旋锁,使用它主要是为了方便实现从Linux最初的SMP过度到细粒度加锁机制。它终将退出历史舞台。BKL的特性:持有BKL的任务仍然可以睡眠 。因为当任务无法调度时,所加的锁会自动被抛弃;当任务被调度时,锁又会被重新获得。当然,并不是说,当任务持有BKL时,睡眠是安全的,紧急是可以这样做,因为睡眠不会造成任务死

19、锁。BKL是一种递归锁。一个进程可以多次请求一个锁,并不会像自旋锁那么产生死锁。BKL可以在进程上下文中。BKL是有害的:在内核中不鼓励使用BKL。一个执行线程可以递归的请求锁lock_kernel(),但是释放锁时也必须调用同样次数的unlock_kernel()操作,在最后一个解锁操作完成之后,锁才会被释放。BKL在被持有时同样会禁止内核抢占。多数情况下,BKL更像是保护代码而不是保护数据。备注:单核不可抢占内核 唯一的异步事件就是硬件中断 ,所以想要同步即关闭中断即可。对于单核可抢占和多核可抢占的 ,除了中断 还有进程调度(即优先级高的进程抢占cpu资源),而上述所有这些机制都是为了防止并发。

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 其他


经营许可证编号:宁ICP备18001539号-1