linux自旋锁

原创 2015年11月17日 17:03:33

1、为什么要有自旋锁

我们写驱动代码的时候,往往忽略这一点,然后版本发布后会经常遇到一些异常的问题,资源的竞争相当重要,很容易出现空指针

引用:
if (!dptr->data[s_pos]) {
dptr->data[s_pos] = kmalloc(quantum, GFP_KERNEL);
if (!dptr->data[s_pos])
goto out;
}
假设有 2 个进程( 我们会称它们为”A”和”B” ) 独立地试图写入同一个 schull 设备的相同偏移. 每个进程同时到达上面片段的第一行的 if 测试. 如果被测试的指针是 NULL,每个进程都会决定分配内存, 并且每个都会复制结果指针给 dptr->datat[s_pos]. 因为2 个进程都在赋值给同一个位置, 显然只有一个赋值可以成功.当然, 发生的是第 2 个完成赋值的进程将”胜出”. 如果进程 A 先赋值, 它的赋值将被进程 B 覆盖. 在此, scull 将完全忘记 A 分配的内存; 它只有指向 B 的内存的指针. A所分配的指针, 因此, 将被丢掉并且不再返回给系统.
事情的这个顺序是一个竞争情况的演示. 竞争情况是对共享数据的无控制存取的结果. 当错误的存取模式发生了, 产生了不希望的东西. 对于这里讨论的竞争情况, 结果是内存泄漏. 这已经足够坏了, 但是竞争情况常常导致系统崩溃和数据损坏. 程序员可能被诱惑而忽视竞争情况为相当低可能性的事件. 但是, 在计算机世界, 百万分之一的事件会每隔几秒发生, 并且后果会是严重的.

2、使用自旋锁注意事项

1、尽可能短时间的拥有锁
2、获取锁之前,要禁止终端,避免无限自旋让系统崩溃

3、自旋锁的一些函数和方法

#include <linux/spinlock.h>
spinlock_t lock = SPIN_LOCK_UNLOCKED;
spin_lock_init(spinlock_t *lock);
定义自旋锁接口的包含文件, 以及初始化锁的 2 个方法.
void spin_lock(spinlock_t *lock);
void spin_lock_irqsave(spinlock_t *lock, unsigned long flags);
void spin_lock_irq(spinlock_t *lock);
void spin_lock_bh(spinlock_t *lock);
加锁一个自旋锁的各种方法, 并且, 可能地, 禁止中断.
int spin_trylock(spinlock_t *lock);
int spin_trylock_bh(spinlock_t *lock);
上面函数的非自旋版本; 在获取锁失败时返回 0, 否则非零.
void spin_unlock(spinlock_t *lock);
void spin_unlock_irqrestore(spinlock_t *lock, unsigned long flags);
void spin_unlock_irq(spinlock_t *lock);
void spin_unlock_bh(spinlock_t *lock);
释放一个自旋锁的相应方法.
rwlock_t lock = RW_LOCK_UNLOCKED
rwlock_init(rwlock_t *lock);
初始化读者/写者锁的 2 个方法.
void read_lock(rwlock_t *lock);
void read_lock_irqsave(rwlock_t *lock, unsigned long flags);
void read_lock_irq(rwlock_t *lock);
void read_lock_bh(rwlock_t *lock);
获得一个读者/写者锁的读存取的函数.
void read_unlock(rwlock_t *lock);
void read_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
void read_unlock_irq(rwlock_t *lock);
void read_unlock_bh(rwlock_t *lock);
释放一个读者/写者自旋锁的读存取.
void write_lock(rwlock_t *lock);
void write_lock_irqsave(rwlock_t *lock, unsigned long flags);
void write_lock_irq(rwlock_t *lock);
void write_lock_bh(rwlock_t *lock);
获得一个读者/写者锁的写存取的函数.
void write_unlock(rwlock_t *lock);
void write_unlock_irqrestore(rwlock_t *lock, unsigned long flags);
void write_unlock_irq(rwlock_t *lock);
void write_unlock_bh(rwlock_t *lock);
释放一个读者/写者自旋锁的写存取的函数.
#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);
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);
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);
原子地存取整数变量. atomic_t 变量必须只通过这些函数存取.
#include <asm/bitops.h>
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);
原子地存取位值; 它们可用做标志或者锁变量. 使用这些函数阻止任何与并发存取
这个位相关的竞争情况.
#include <linux/seqlock.h>
seqlock_t lock = SEQLOCK_UNLOCKED;
seqlock_init(seqlock_t *lock);
定义 seqlock 的包含文件, 已经初始化它们的 2 个方法.
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);
获得一个 seqlock-保护 的资源的读权限的函数.
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);
获取一个 seqlock-保护的资源的写权限的函数.
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);
释放一个 seqlock-保护的资源的写权限的函数.
#include <linux/rcupdate.h>
需要使用读取-拷贝-更新(RCU)机制的包含文件.
void rcu_read_lock;
void rcu_read_unlock;
获取对由 RCU 保护的资源的原子读权限的宏定义.
void call_rcu(struct rcu_head *head, void (*func)(void *arg), void *arg);
安排一个回调在所有处理器已经被调度以及一个 RCU-保护的资源可用被安全的释
放之后运行.
版权声明:喜欢linux

Linux内核自旋锁

自旋锁 自旋锁(spinlock)是用在多个CPU系统中的锁机制,当一个CPU正访问自旋锁保护的临界区时,临界区将被锁上,其他需要访问此临界区的CPU只能忙等待,直到前面的CPU已访问完临界区,将...
  • Tommy_wxie
  • Tommy_wxie
  • 2012年02月22日 14:33
  • 7105

Linux 自旋锁

1.什么是自旋锁 自旋锁顾名思义首先是一把锁,另外使用这把锁的线程需要反复自我循环(loop)检测这把锁是否可用。 注意与信号量区别,信号量也是一把锁,但是使用这把锁的线程检测锁不可用时,选择去睡...
  • xiaofei0859
  • xiaofei0859
  • 2014年04月14日 00:01
  • 2133

linux kernel 信号量、互斥锁、自旋锁

1.信号量1.1 概念信号量又称为信号灯(semaphore),本质上信号量是一个计数器,它用来记录对某个资源(如共享内存)的存取状况。一般说来,为了获得共享资源,进程需要执行下列操作:    (...
  • u012719256
  • u012719256
  • 2016年09月26日 14:42
  • 2097

linux内核自旋锁总结

1、自旋锁实现: 自旋锁是一个互斥设备,它只有两个值:“锁定”和“解锁”。它通常实现为某个整数值中的某个位。希望获得某个特定锁得代码测试相关的位。如果锁可用,则“锁定”被设置,而代码继续进入临界区;相...
  • xiaoaide01
  • xiaoaide01
  • 2016年07月06日 16:29
  • 1082

Linux 同步机制:自旋锁

自旋锁的特点与适用场景Linux自旋锁spinlock同一时刻只能被一个可执行线程持有。当一个线程试图获取一个已经被持有的spin lock时,就会一直忙循环-选择-等待锁重新可用。忙等待免去了线程挂...
  • thisinnocence
  • thisinnocence
  • 2017年01月17日 23:29
  • 372

深入分析Linux自旋锁

转载:http://blog.chinaunix.net/uid-26990992-id-3264808.html 前言:       在复习休眠的过程中,我想验证自旋锁中不可休眠,所以编...
  • chinaclock
  • chinaclock
  • 2015年11月25日 10:11
  • 849

linux并发控制之自旋锁

自旋锁是一种对临界资源进行互斥访问的典型手段,其名来源于它的工作方式。 通俗的讲,自旋锁就是一个变量,该变量把一个临界区标记为“我当前在运行,请等待”或者标记为“我当前不在运行,可以被使用”, 如果...
  • williamwang2013
  • williamwang2013
  • 2013年01月18日 16:26
  • 1070

自旋锁和互斥锁区别

http://blog.csdn.net/kyokowl/article/details/6294341 POSIX threads(简称Pthreads)是在多核平台上进行并行编程的一套常...
  • sunmenggmail
  • sunmenggmail
  • 2012年10月24日 08:55
  • 55309

linux内核自旋锁和中断知识讲解

一、并发与竞态三个要点 1、只要并发的执行单元同时访问共享内存是就会出现竞态 2、解决竞态的唯一途径是保证共享资源的互斥访问,即一个执行单元在访问共享资源时,其他的执行单元被禁止访...
  • wangteng12345678
  • wangteng12345678
  • 2016年08月02日 16:42
  • 1151

linux驱动之自旋锁(spinlock)

dasads
  • u013256018
  • u013256018
  • 2015年09月08日 19:30
  • 1064
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:linux自旋锁
举报原因:
原因补充:

(最多只允许输入30个字)