semaphore:
信号量的特点:
1、用于进程与进程之间的同步
2、允许有多个进程进入临界区代码执行
3、进程获取不到信号量锁会陷入休眠,并让出cpu
4、被信号量锁保护的临界区代码允许休眠
5、本质是基于进程调度器,UP和SMP下的实现无差异
6、不支持进程和中断之间的同步
实际操作:
struct semaphore sema;//定义信号量变量
在驱动初始化代码中:
eg:
int hello_int(void)
{
.......
sema_init(&seme, 1);//只允许一个进程运行
.......
}
int hello_open(struct inode *p, struct *f)
{
down(&sema);//加锁
if(open_count >= 1)
{
up(&sema);
prink(KERN_INFO "device is busy, hello_open fail);
return -EBUSY;
}
open_count++;
up(&sema);
prink(KERN_INFO "device is busy, hello_open ok");
return 0;
}
int hello_close(struct inode *p, struct *f)
{
if(open_count != 1)
{
up(&sema);
prink(KERN_INFO "device is busy, hello_open fail);
return -EBUSY;
}
open_count--;
up(&sema);
prink(KERN_INFO "device is busy, hello_open ok");
return 0;
}
spinlock
自旋锁的特点:
1、spinlock是一个死等的锁机制
2、semaphore可以允许多个执行单元进入,spinlock不行,一次只能有一个执行单元获取锁并进入临界区,
其他的执行单元都是在门口不断的死等
3、spinlock的执行时间短,由于spinlock死等这种特性,如果临界区执行时间太长,
那么不断在临界区门口"死等"的那些执行单元就很浪费CPU资源
4、spinlock可以在终端上下文执行,由于不睡眠,因此spinlock可以在中断上下文使用
实际操作:
spinlock count_lock;//定义锁
在驱动初始化代码中:
eg:
int hello_int(void)
{
.......
spin_lock_init(&count_lock);//初始化
.......
}
int hello_open(struct inode *p, struct *f)
{
spin_lock(&count_lock);//加锁
//临界区代码
if(open_count >= 1)
{
spin_unlock(&count_lock);
prink(KERN_INFO "device is busy, hello_open fail);
return -EBUSY;
}
open_count++;
spin_unlock(&count_lock);
prink(KERN_INFO "device is busy, hello_open ok");
return 0;
}
int hello_close(struct inode *p, struct *f)
{
if(open_count != 1)
{
spin_lock(&count_lock);
prink(KERN_INFO "device is busy, hello_open fail);
return -EBUSY;
}
open_count--;
spin_unlock(&count_lock);
prink(KERN_INFO "device is busy, hello_open ok");
return 0;
}
spinlock的系列函数:
//进程与进程之间的同步
void spin_lock(spinlock_t *lock)
//涉及到和本地软中断之间的同步
void spin_lock_bh(spinlock_t *lock)
//涉及到和本地硬件中断之间的同步
void spin_lock_irq(spinlock_t *lock)
//涉及到和本地硬件中断之间的同步并保存本地中断状态
void spin_lock_irqsave(lock, flags)
//尝试获取锁,如果成功返回非零值,否则返回零值
int spin_trylock(spinlock_t *lock)
spinlock、rw spinlock、seqlock、rcu机制比较:
1、rw(read/write)spinlock
1.1、加锁的逻辑
(1)假设临界区没有任何的thread,这时候任何read thread或者write thread可以进入;
(2)假设临界区内有一个read thread,这时候新来的read thread可以任意进入,但是write thread不可以进入;
(3)假设临界区内有一个write thread,这时候任何的read thread或者write thread都不可以进入;
(4)假设临界区内有一个或者多个read thread,write thread当然不可以进入临界区,但是该write thread也无法阻止后续read thread的进入
他要一直等到临界区一个read thread也没有的时候,才能进入。
由此可见,rw spinlock给reader赋予了更高的优先级。
2、seqlock(顺序锁)
2.1、加锁的逻辑
(1)假设临界区没有任何的thread,这时候任何read thread或者write thread可以进入;
(2)假设临界区没有一个write thread,read thread可以随意进入,也就是说reader不会阻挡reader;
(3)假设临界区有一个write thread,这时候任何的read thread或者write thread都不可以进入;
(4)假设临界区只有read thread时,write thread可以立刻执行,不会等待
由此可见,seqlock给writer赋予了更高的优先级。
3、spinlock的不足
3.1、性能问题:
RW spin lock、spin lock和seqlock,它们都是基于一个memory中的共享变量(对该变量的访问是原子的)
4、各个锁机制比较
(1)spin lock不区分reader和writer,对于那些读写强度不对称的是不合适的;
(2)RW spin lock和seq lock解决了这个问题,不过seq lock倾向于writer,而RW spin lock更照顾reader;
(3)为什么还有RCU?
随着计算机硬件技术的发展,CPU相对于存储器件的运算速度优势越来越大,在这种背景下,
获取基于counter(需要访问存储期间)的锁(例如spin lock、rw lock)的机制开销越来越明显。
因此,那些基于一个multi-processor之间的共享的counter的锁机制已经不能满足性能的需求,
这也就有了RCU机制