Linux并发控制

来源:互联网 发布:java wait 例子 编辑:程序博客网 时间:2024/05/17 03:01

自旋锁


自旋锁是专为防止多处理器并发而引入的一种锁,它应用于中断处理等部分。对于单处理器来说,防止中断处理中的并发可简单采用关闭中断的方式,不需要自旋锁。自旋锁最多只能被一个内核任务持有,如果一个内核任务试图请求一个已被争用(已经被持有)的自旋锁,那么这个任务就会一直进行忙循环——旋转——等待锁重新可用。要是锁未被争用,请求它的内核任务便能立刻得到它并且继续进行。自旋锁可以在任何时刻防止多于一个的内核任务同时进入临界区,因此这种锁可有效地避免多处理器上并发运行的内核任务竞争共享资源。

使用方法:

1.定义自旋锁变量

spinlock_t lock;

2.初始化自旋锁变量

spin_lock_init(&lock);

注:1,2可以使用宏DEFINE_SPINLOCK(lock);

#define DEFINE_SPINLOCK(x)  spinlock_t x = _SPIN_LOCK_UNLOCKED(x)

3.获取自旋锁

spin_lock(&lock); //成功获得则函数立即返回,如果未获取自旋锁。spin_lock函数会被阻塞直到获取自旋锁才返回。

spin_trylock(&lock);//成功获得自旋锁与否,都将立即返回。成功则返回非0值,失败返回0

4.释放自旋锁

spin_lock(&unlock);

自旋锁主要针对SMP(对称多处理)或单CPU但内核可抢占的情况。对于单CPU并且不支持内核抢占的系统,自旋锁将退化为空操作。尽管使用自旋锁可以保证临界区不会被干扰,但是执行临界区代码时仍然会受到中断和底半部的影响。为了避免这种情况的发生,就需要用到自旋锁的衍生:如下:

//void spin_lock_irq(spinlock_t *lock)    获取自旋锁并禁止中断

//void spin_lock_bh(spinlock_t *lock)    获取自旋锁并禁止底半部

//void spin_is_locked(spinlock_t *lock) 如果自旋锁已经被占用返回非0值,否则返回0

自旋锁实际上是盲等锁,当锁被占用的时候,CPU会一直循环执行"测试自旋锁"动作。在此期间不做任何有用的工作,仅仅是等待。只有在占用时间极端的情况下使用自旋锁才是合理的。不恰当的使用自旋锁还有可能导致系统死锁。引发的情况是递归的使用自旋锁。


读写自旋锁

自旋锁并不关心锁定的临界区是读还是写,都只允许同时只有一个执行单元获得自旋锁。实际上对于并发访问共享资源时,多个执行单元同时读取时没有问题的。为了解决这个问题,自旋锁衍生了读写自旋锁。也就是说读,写操作分开。多个执行单元可以同时获得读自旋锁,但只能获得一个写自旋锁。如果已经获得了一个读自旋锁,那么再获得写自旋锁的时候就需要读自旋锁的释放。


使用方法:

1.定义读写自旋锁变量

rwlock_t lock;

2.初始化读写自旋锁变量

rwlock_init(&lock);

注:1,2可以使用宏DEFINE_RWLOCK(lock);

#define DEFINE_RWLOCK(x)  rwlock_t x = _RW_LOCK_UNLOCKED(x)

3.获取读写自旋锁

read_lock(&lock); //读自旋锁,成功获得则函数立即返回,如果未获取读自旋锁。read_lock函数会被阻塞。

read_trylock(&lock);//成功获得读自旋锁与否,都将立即返回。成功则返回非0值,失败返回0

write_lock(&lock); //写自旋锁,成功获得则函数立即返回,如果未获取写自旋锁。write_lock函数会被阻塞。

write_trylock(&lock);//成功获得写自旋锁与否,都将立即返回。成功则返回非0值,失败返回0

注:不能同时申请读自旋锁和写自旋锁,否则会导致死锁。

4.释放读写自旋锁

read_unlock(&unlock);

write_unlock(&unlock);


顺序锁

顺序锁与读写自旋锁类似,只是赋予了写锁更高的权限,在获取读锁的同时仍然可以获得写锁。也就是写锁永远不会被阻塞除了被另一个写锁阻塞。

使用方法:

typedef struct {

unsigned sequence;

spinlock_t lock;

} seqlock_t;

在获取顺序锁时,seqlock_t.sequence变量会被加1,释放时仍会被加1.因此,所以在未释放时时奇数,释放后是偶数。

1.定义顺序锁变量

seqlock_t lock;

2.初始化顺序锁变量

seqlock_init(&lock);

注:1,2可以使用宏DEFINE_SEQLOCK(lock);

3.获取顺序锁

read_seqbegin(&lock);

read_seqretry(&lock,seq)

unsigned seq

do{

     seq = read_seqbegin(&lock);

}while(read_seqretry(&lock,seq));

write_seqlock(&lock); //写顺序锁,成功获得则函数立即返回,如果未获取顺序锁。read_lock函数会被阻塞直到获取顺序锁才返回。

write_tryseqlock(&lock);//成功获得顺序锁与否,都将立即返回。成功则返回非0值,失败返回0

注:不能同时申请读自旋锁和写自旋锁,否则会导致死锁。

4.释放顺序锁

write_sequnlock(&unlock);




0 0
原创粉丝点击