nullnullLinux同步机制Linux同步机制李翌日期:2007年11月22日概述概述内核同步的类型:
与中断的同步
多线程的同步
SMP
内核抢占概述概述原子手段忙等同步睡眠同步复杂简单效率低效率高atomiclock_int
spin_lock mutex
read write sem
....其它同步手段RCU
PerCPU DATA
preempt disable注意:这里的效率高低只是同步手段本身的效率,但是否在实际中效率高低要根据使用的上下文环境具体分析概述概述from ULK IIIPerCPU DataPerCPU Data每个CPU使用独有的数据
针对多CPU访问,从根本上避免锁的使用
最快的方法(比使用原子操作快5%左右)
若有本CPU异步同步要求(中断或softIRQ),则另需要同步手段
使用:
DEFINE_PER_CPU(type, name)
per_cpu(name, cpu)
AtomicAtomic原子性
操作中不用考虑中断打断问题
实现总线锁定,不用考虑其它CPU同步问题
使用:
对基本数据类型的同步:int,bits
不能保证两个或多个数据的同步
比其它同步手段效率高,可以作为构建其它复杂同步手段使用
不应看作简单的变量修改、获取操作,它涉及到cache 的刷新和总线的锁定,有一定的开销AtomicAtomic修改操作:
修改并返回结果操作:atomic_set(); set_bit();
clear_bit(); change_bit();
atomic_add(); atomic_sub();
atomic_inc(); atomic_dec();xchg(); cmpxchg();
atomic_cmpxchg(); atomic_inc_return();
atomic_dec_return(); atomic_add_return();
atomic_sub_return(); atomic_inc_and_test();
atomic_dec_and_test(); atomic_sub_and_test();
atomic_add_negative(); atomic_add_unless();
test_and_set_bit(); test_and_clear_bit();
test_and_change_bit();AtomicAtomic任何修改数值并返回的atomic操作都有隐含的mem barrier
任何只修改数值不返回的atomic操作,linux不保证barrier操作!
ULK:Notice that in multiprocessor systems, all atomic operations described in the earlier section "Atomic Operations" act as memory barriers because they use the lock byte.只针对X86!int_lock & preempt disableint_lock & preempt disable单CPU的同步手段
效率高,不影响吞吐量
影响实时性spin_lockspin_lock多CPU的同步手段
Spin_lock:
preempt Disable;
LOCK{ for(;lock;); lock++; }
在单CPU下退化为空指令:
在抢占内核下,退化为禁止抢占指令
在非抢占内核下,完全退化为空操作
若内核配置上Spin_lock debug,则不论是否配置成了SMP,都会启动spin_lock为什么需要禁止抢占?spin_lockspin_lock同一CPU上获取两次spin_lock,必会导致死锁。
现象:无异常打印但系统无反映
Spin_lock是忙等操作,影响吞吐量
使用:
当在SMP下的多个CPU下需要同步数据访问时
当访问数据时间很短,低于线程切换时间
spin_lockspin_lock_init()
Runtime initializing given spinlock_t
spin_lock() / spin_unlock()
Acquire or release given lock
spin_lock_irq() / spin_unlock_irq()
Disable local interrupts and acquire given lock
Release given lock and enable local interrupts
spin_lock_irqsave() / spin_unlock_irqrestore()
Save current state of local interrupts, disable local interruptsand acquire given lock
Release given lock and restore local interrupts to given previous state
spin_trylock()
Try to acquire given lock; if unavailable, returns zero
spin_islocked() :Return nonzero if the given lock is currently acquiredspin_lockr/w spin lockr/w spin lock允许多个读操作同时,对写进行同步。
适合与对更改操作远少于读取操作的数据结构
使用:rw_lock_init(), rw_is_locked()
read_lock(), read_lock_irq(), ......
write_lock(), write_lock_irq(), ......r/w spin lockr/w spin lock实现:
rwlock_t是其lock结构,其锁字段为32bits整数,初始化为 0x01000000
获取write锁,按照 0x01000000来获取
获取read锁,按照1来获取seq lockseq lock与read_write spin lock 类似,是不对称锁
偏向于write操作,可以在有read操作时候获取到write锁
使用:
seq lockseq lock实现:
typedef struct {
unsigned sequence;
spinlock_t lock;
}seqlock_t; static inline void write_seqlock(seqlock_t *sl) {
spin_lock(&sl->lock);
++sl->sequence;
smp_wmb();
}static inline void write_sequnlock(seqlock_t *sl) {
smp_wmb();
++sl->sequence;
spin_unlock(%sl->lock);
}seq lockseq lock实现:
SemaphoresSemaphores实现可睡眠的等待
使用:
当实现较长时间的等待操作
只能在进程(线程)上下文中使用
可以实现较复杂的类型:
二进制、互斥、计数信号量
FIFO,Priority等待队列
优先级继承
重入、delete safe ...SemaphoresSemaphoresatomically transforms a write lock into a read lock CompletionCompletion通知事件完成,只能使用一次
以下场合,使用sem的问题:
两个线程同步,线程1创建一个MUTEX,并设置成获取状态,传递给线程2,同时执行Down操作等待该信号量
线程2执行完某操作后,执行UP,释放这个MUTEX
线程1唤醒,直接删除该MUTEX
问题:可能线程1的Down和线程2的down同时执行,当线程2执行到释放该MUTEX时,线程1还在UP操作中,引发错误。Linux 上实现Linux 上实现RCU目的
对于有大量读操作性能极大提升,读操作不用获取任何互斥信号
实现:
首要条件:
所有CPU上,对齐地址的存储操作都是原子的
对引用方式使用的变量有效A=1A=2A=9A=4Linux 上实现Linux 上实现RCU读写回收rcu_assign_pointer()Protect:
rcu_read_lock()
rcu_read_unlock()rcu_dereference()Defer:
synchronize_rcu() & call_rcu()Linux 上实现Linux 上实现RCU#define rcu_assign_pointer(p, v)
({ \
smp_wmb(); \
(p) = (v); \
})#define rcu_dereference(p)
({ \
typeof(p) ___p1 = p; \
smp_read_barrier_depends(); \
(___p1); \
})Linux 上实现Linux 上实现RCURCU 示例RCU 示例总结总结根据上下文情况选择同步手段
读写频率
临界区大小
执行上下文
smp vs up
同步手段应在
设计
领导形象设计圆作业设计ao工艺污水处理厂设计附属工程施工组织设计清扫机器人结构设计
时确定
同步手段在理解其原理后才能使用,否则应使用简单的方式null