您好,欢迎访问三七文档
Linux内核并发控制并发、竞态与临界区并发(concurrency)指的是多个执行单元同时、并行被执行。并发的执行单元对共享资源(硬件资源、全局变量、静态变量等)的访问很容易导致竞态(racecondition)访问共享资源的代码区域成为临界区(criticalsections),临界区必须用某种互斥机制加以保护。造成竞态的主要原因:•对称多处理器(SMP)•进程调度与抢占•中断与进程之间的竞争•中断与中断之间的竞争中断屏蔽单CPU范围内避免竞态的一种简单而省事的方法。一旦中断被屏蔽,进程调度也不会发生。缺点是很多硬件事件不能得到及时处理local_irq_disable();……criticalsection……local_irq_enable();local_irq_save(flags);local_irq_restore(flags);local_bh_disable();local_bh_enable();原子变量原子变量(atomic_t)是一个结构体,能够保存一个24bit整数Linux内核保证对于原子变量的相关操作具有原子性。atomic_tcount=ATOMIC_INIT(0);voidatomic_add(inti,atomic_t*v);intatomic_read(atomic_t*v);voidatomic_add(inti,atomic_t*v);voidatomic_sub(inti,atomic_t*v);voidatomic_inc(atomic_t*v);voidatomic_dec(atomic_t*v);intatomic_inc_and_test(atomic_t*v);intatomic_dec_and_test(atomic_t*v);intatomic_sub_and_test(inti,atomic_t*v);intatomic_add_return(inti,atomic_t*v);intatomic_sub_return(inti,atomic_t*v);intatomic_inc_return(atomic_t*v);intatomic_dec_return(atomic_t*v);原子位操作利用原子位操作能够保证对内存中某个变量的相关位操作具有原子性。voidset_bit(intnr,void*addr);voidclear_bit(intnr,void*addr);voidchange_bit(intnr,void*addr);inttest_bit(intnr,void*addr);inttest_and_set_bit(intnr,void*addr);inttest_and_clear_bit(intnr,void*addr);inttest_and_change_bit(intnr,void*addr);自旋锁自旋锁有“加锁”和“解锁”两种状态.它常常实现为一个整数值中的单个位.想获取锁的执行单元测试相关的位.如果锁是可用的,这个“加锁”位被置位并且代码继续进入临界区.相反,如果这个锁已经被别人获得,代码进入一个循环中反复检查这个锁,直到它变为可用.这个循环就是自旋部分使用自旋锁的主要事项:1.占有临界区的时间必须要短;2.拥有自旋锁期间所在CPU的进程抢占被关闭;3.占有自旋锁期间不能调用引起阻塞的函数(原子上下文)4.自旋锁可以被用于中断上下文自旋锁相关内核函数spinlock_tmy_lock=SPIN_LOCK_UNLOCKED;voidspin_lock_init(spinlock_t*lock);voidspin_lock(spinlock_t*lock);voidspin_lock_irqsave(spinlock_t*lock,unsignedlongflags);voidspin_lock_irq(spinlock_t*lock);voidspin_lock_bh(spinlock_t*lock);voidspin_unlock(spinlock_t*lock);voidspin_unlock_irqrestore(spinlock_t*lock,unsignedlongflags);voidspin_unlock_irq(spinlock_t*lock);voidspin_unlock_bh(spinlock_t*lock);intspin_trylock(spinlock_t*lock);intspin_trylock_bh(spinlock_t*lock);几种经过特殊优化的自旋锁读写自旋锁:允许同时读,不允许同时写,写时禁止读,写操作优先级高于读操作;顺序锁:读可以随时进行,读时可以写,但不允许多个执行单元同时写,为了防止读的内容失效,读完必须检测所读内容的有效性;RCU锁:读-拷贝-更新锁,对经常读而极少写的情况作了优化。信号量一个信号量是一个单个整型值,结合有一对函数,典型地称为P和V.一个想进入临界区的进程将在相关旗标上调用P;如果信号量的值大于零,这个值递减1并且进程继续.相反,如果信号量的值是0(或更小),进程进入休眠等待直到别人释放信号量.锁一个信号量通过调用V完成;这个函数递增信号量的值,并且,如果需要,唤醒等待的进程.信号量是进程级的。当进程占有资源时间较长时,用信号量是最佳选择。拥有信号量期间也可以进入休眠;信号量不能被用于中断上下文信号量的实现structsemaphore{spinlock_tlock;unsignedintcount;structwait_queue_twait_list;}信号量相关内核函数voidsema_init(structsemaphore*sem,intval);DECLARE_MUTEX(name);DECLARE_MUTEX_LOCKED(name);voidinit_MUTEX(structsemaphore*sem);voidinit_MUTEX_LOCKED(structsemaphore*sem);voiddown(structsemaphore*sem);intdown_interruptible(structsemaphore*sem);intdown_trylock(structsemaphore*sem);voidup(structsemaphore*sem);读写信号量voidinit_rwsem(structrw_semaphore*sem);voiddown_read(structrw_semaphore*sem);intdown_read_trylock(structrw_semaphore*sem);voidup_read(structrw_semaphore*sem);voiddown_write(structrw_semaphore*sem);intdown_write_trylock(structrw_semaphore*sem);voidup_write(structrw_semaphore*sem);voiddowngrade_write(structrw_semaphore*sem);完成量一个线程可以利用完成量(completion)告诉另外一个线程某个事件已经发生(或某个工作已经完成),可以在此基础上做你想做的另一件事情了。structcompletionmy_completion;init_completion(&my_completion);DECLARE_COMPLETION(my_completion);voidwait_for_completion(structcompletion*c);voidcomplete(structcompletion*c);voidcomplete_all(structcompletion*c);
本文标题:Linux并发控制
链接地址:https://www.777doc.com/doc-3146720 .html