自旋锁

 

自旋锁和信号量的使用要点
(1)自旋锁不能递归
(2)自旋锁可以用在中断上下文(信号量不可以,因为可能睡眠),但是在中断上下文中获取自旋锁之前要先禁用本地中断
(3)自旋锁的核心要求是:拥有自旋锁的代码必须不能睡眠,要一直持有CPU直到释放自旋锁
(4)信号量和读写信号量适合于保持时间较长的情况,它们会导致调用者睡眠,因此只能在进程上下文使用,而自旋锁适合于保持时间非常短的情况,它可以在任何上下文使用。如果被保护的共享资源只在进程上下文访问,使用信号量保护该共享资源非常合适,如果对共享资源的访问时间非常短,自旋锁也可以。但是如果被保护的共享资源需要在中断上下文访问(包括底半部即中断处理句柄和顶半部即软中断),就必须使用自旋锁。自旋锁保持期间是抢占失效的,而信号量和读写信号量保持期间是可以被抢占的。自旋锁只有在内核可抢占或SMP(多处理器)的情况下才真正需要,在单CPU且不可抢占的内核下,自旋锁的所有操作都是空操作。

自旋锁使用函数:

spinlock_t *lock

spin_lock_init();//初始化

spin_lock() ; //上锁

spin_unlock() ;//解锁

一个信号量(semaphore: 旗语,信号灯)本质上是一个整数值,它和一对函数联合使用,这一对函数通常称为P和V。

希望进入临届区的进程将在相关信号量上调用P;如果信号量的值大于零,则该值会减小一,而进程可以继续。相反,如果信号量的值为零(或更小),进程必须等待知道其他人释放该信号。

对信号量的解锁通过调用V完成;该函数增加信号量的值,并在必要时唤醒等待的进程。


当信号量用于互斥时(即避免多个进程同是在一个临界区运行),信号量的值应初始化为1。这种信号量在任何给定时刻只能由单个进程或线程拥有。在这种使用模式下,一个信号量有事也称为一个“互斥体(mutex)”,它是互斥(mutual exclusion)的简称。Linux内核中几乎所有的信号量均用于互斥。
使用信号量,内核代码必须包含<asm/semaphore.h> 。

信号量的创建与初始化
1.void sema_init(struct semaphore *sem,int val);
   其中val是赋予一个信号量的初始值

 
P函数为:
void down(struct semaphore*sem);/*不推荐使用,会建立不可杀进程*/


int down_interruptible(struct semaphore*sem);/*推荐使用,使用down_interruptible需要格外小心,若操作被中断,该函数会返回非零值,而调用这不会拥有该信号量。对down_interruptible的正确使用需要始终检查返回值,并做出相应的响应。*/


int down_trylock(struct semaphore*sem);/*带有“_trylock”的永不休眠,若信号量在调用是不可获得,会返回非零值。*/

 
V函数为:
void up(struct semaphore*sem);/*任何拿到信号量的线程都必须通过一次(只有一次)对up的调用而释放该信号量。在出错时,要特别小心;若在拥有一个信号量时发生错误,必须在将错误状态返回前释放信号量。*/

#include<linux/module.h>
#include<linux/init.h>
#include <linux/fs.h>
#include <linux/cdev.h>
#include <asm/uaccess.h>
#include <linux/device.h>  /** udev **/
 
struct cdev cdev;
dev_t devno;
static struct class* test_class;  /** udev **/
static struct device* test_device;  /** udev **/
 
struct semaphore sem; /** sem **/
 
int test_open(struct inode *inode, struct file *filp)
{
	if( !down_trylock(&sem) )
	{
		printk("test_open ok \n");
		return 0;
	}
	else
	{
		printk("test_open error\n");
		return -1;
	}
	return 0;
	
}
 
int test_release(struct inode *inode, struct file *filp)
{
	up(&sem);
	return 0;
}
 
static ssize_t test_read(struct file *filp, char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}
 
static ssize_t test_write(struct file *filp, const char __user *buf, size_t size, loff_t *ppos)
{
	return 0;
}
 
static const struct file_operations test_fops =
{
  .read = test_read,
  .write = test_write,
  .open = test_open,
  .release = test_release,
};
 
static int test_init(void)
{
	cdev_init(&cdev,&test_fops);
	alloc_chrdev_region(&devno, 0, 1, "test");
	cdev_add(&cdev, devno, 1);
	
    test_class = class_create(THIS_MODULE, "testdrv"); /** udev **/ 
    if(IS_ERR(test_class)){  
        printk(KERN_ERR "create class error!\n");  
    } 	
    test_device = device_create(test_class, NULL, devno, NULL, "test"); /** udev **/ 
    
    sema_init(&sem,1);/** sem **/
	printk("test_init\n");
	return 0;	
}
 
static void test_exit(void)
{
	device_destroy(test_class, devno);/** udev **/
	class_destroy(test_class); /** udev **/
	
	cdev_del(&cdev);
	unregister_chrdev_region(devno, 1);
	printk("test_exit\n");
}
 
module_init(test_init);
module_exit(test_exit);
MODULE_LICENSE("GPL");


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值