关于Linux自旋锁
既然是对一个变量进行保护,当然是一个自旋锁了,还没见过一个变量能当两个用的。
我觉得你对这段代码的理解有问题,用 spin_lock 和 spin_unlock 的目的是保证程序在对 xxx_lock 进行操作的时候,不会有其它进程改变这个值,是为了保证数据的准确性。
你可以设想一下,如果没有自旋锁,代码运行起来会有什么问题。假设 A,B两个进程同时访问 open , 没有使用自旋锁,此时 xxx_lock=0, A 进程在判断 if (xxx_count) 时,会认为设备没有被使用,那么它会继续后面的 xxx_count++ 操作,但假如这时 CPU 切换进程, A 进程还没有来得及把 xxx_count 变成 1 的时候, B 进程开始运行,那么 B 进程此时也会认为设备没有被使用,它也会进行后继操作,这样就会出现两个进程同时访问设备的错误。
open 和 release 当然可以同时访问,只不过在运行 spin_lock 的时候,后访问的进程会被阻塞而已。假设有 A 进程访问 open ,B 进程访问 release ,你可以把这种情况理解为 A , B 进程同时访问 open 函数,这样或许能更好的理解这段代码。因为 open 和 release 在使用自旋锁的时候,方法是一样的。
spin_lock 和 CPU 系统无关,不管是单 CPU 还是多 CPU ,运行结果都是一样的。
这个逻辑关系比较难解释,不知道你看懂我的意思没。
android为什么不支持spin lock
首先看下,spin_lock的实现:
[cpp] view plain copy
static inline void spin_lock(spinlock_t *lock)
{
raw_spin_lock(&lock->rlock);
}
[cpp] view plain copy
#define raw_spin_lock(lock) _raw_spin_lock(lock)
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{
__raw_spin_lock(lock);
}
[cpp] view plain copy
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{
preempt_disable();
spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);
LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_loc
自旋锁的自旋锁-实现
在单处理机环境中可以使用特定的原子级汇编指令swap和test_and_set实现进程互斥,(Swap指令:交换两个内存单元的内容;test_and_set指令取出内存某一单元(位)的值,然后再给该单元(位)赋一个新值,关于为何这两条指令能实现互斥我们不在赘述,读者可以了解其算法) 这些指令涉及对同一存储单元的两次或两次以上操作,这些操作将在几个指令周期内完成,但由于中断只能发生在两条机器指令之间,而同一指令内的多个指令周期不可中断,从而保证swap指令或test_and_set指令的执行不会交叉进行.但在多处理机环境中情况有所不同,例如test_and_set指令包括“取”、“送”两个指令周期,两个CPU执行test_and_set(lock)可能发生指令周期上的交叉,假如lock初始为0, CPU1和CPU2可能分别执行完前一个指令周期并通过检测(均为0),然后分别执行后一个指令周期将lock设置为1,结果都取回0作为判断临界区空闲的依据,从而不能实现互斥. 如图4-3所示.为在多CPU环境中利用test_and_set指令实现进程互斥,硬件需要提供进一步的支持,以保证test_and_set指令执行的原子性. 这种支持目前多以“锁总线”(bus locking)的形式提供的,由于test_and_set指令对内存的两次操作都需要经过总线,在执行test_and_set指令之前锁住总线,在执行test_and_set指令后开放总线,即可保证test_and_set指令执行的原子性,用法如下:算法4-6:多处理机互斥算法(自旋锁算法)do{b=1;while(b){lock(bus);b = test_and_set(&lock);unlock(bus);}临界区lock = 0;其余部分}while(1)总之,自旋锁是一种对多处理器相当有效的机制,而在单处理器非抢占式的系统中基本上没有作用。自旋锁在SMP系统中应用得相当普遍。在许多SMP系统中,允许多个处理机同时执行目态程序,而一次只允许一个处理机执行操作系统代码,利用一个自旋锁可以很容易实现这种控制.一次只允许一个CPU执行核心代码并发性不够高,若期望核心程序在多CPU之间的并行执行,将核心分为若干相对独立的部分,不同的CPU可以同时进入和执行核心中的不同部分,实现时可以为每个相对独立的区域设置一个自旋锁.
关于旋转锁(spin lock)的解释
spin lock一般翻译为自旋锁,简单的理解是这样的,它和信号量差不多。 信号量:线程在无信号时会阻塞,阻塞时会释放CPU,让其它线程用。 自旋锁:自旋锁在得不到锁的状态下也会阻塞,但阻塞时不释放CPU,一直占用CPU,相当于在死循环。 如果想看比较专业的解释,可以参考: http://baike.baidu.com/view/1250961.html?wtp=tt
linux自旋锁使用时需要注意的几个地方
1、在内核多线程编程时,为了保护共享资源通常需要使用锁,而使用的比较多的就是spinlock,但需要注意的是:所有临界区代码都需要加锁保护,否则就达不到保护效果。也就是,访问共享资源的多个线程需要协同工作共同加锁才能保证不出错。在实际写代码时,有时候会网掉这一点,以致出现各种稀奇古怪的问题,而且很难找到原因。2、在出现两个和多个自旋锁的嵌套使用时,务必注意加锁和解锁的顺序。比如:在线程1中,spinlock A -> spinlock B -> spin unlock B -> spin unlock A ;那么,在需要同步的线程2中,若需要加相同的锁,则顺序也应该保持相同,spinlock A -> spinlock B -> spin unlock B -> spin unlock A ;否则,很有可能出现死锁。3、spinlock保护的代码执行时间要尽量短,若有for循环之类的代码,则一定要确保循环可以在短时间可以退出,从而使得spinlock可以释放。4、spinlock所保护的代码在执行过程中不能睡眠。比如,在spinlock和spinunlock之间不能调用kmalloc, copy_from_user,kthread_stop等调用,因为这些函数调用均有可能导致线程睡眠。5、spinlock在实际使用时有如下几种类型,spin_lock,spin_lock_bh,spin_lock_irqsave。在具体使用时,需要根据被保护临界区锁处的上下文选择合适的spinlock类型。spin_lock用于不同cpu线程间同步,spin_lock_bh和spin_lock_irqsave主要用于本cpu线程间的同步,前者关软中断,后者关硬中断。
多线程中Semaphore,mutex和lock的区别
mutex互斥体只用于保护临界区的代码(访问共享资源),而不用于锁之间的同步,即一个线程释放mutex锁后,马上又可能获取同一个锁,而不管其它正在等待该mutex锁的其它线程。
semaphore信号量除了起到保护临界区的作用外,还用于锁同步的功能,即一个线程释放semaphore后,会保证正在等待该semaphore的线程优先执行,而不会马上在获取同一个semaphore。
如果两个线程想通过一个锁达到输出1,2,1,2,1,2这样的序列,应使用semaphore, 而使用mutex的结果可能为1,1,1,1,1,2,2,2,111.....。