Linux内核的竞态与并发——信号量实例

《信号量实例》


所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!

关于 LINUX驱动 的其它文章请点击这里:     LINUX驱动


本文为 Linux内核的竞态与并发(中断屏蔽、原子操作、自旋锁、信号量、互斥体的互斥机制) 中原子操作的实例

其他部分:
Linux内核的竞态与并发——原子操作实例
Linux内核的竞态与并发——自旋锁实例


信号量使用步骤

 // 1)定义一个信号量   
 	struct semaphore btn_sem;
 	
 // 2) 初始化信号量          
 	void sema_init(&btn_sem, 5);    //该信号量可以被5个执行单元持有
    //还可以通过以下宏完成信号量的定义和赋值为1             
    DEFINE_SEMAPHORE(btn_sem);
    
 // 3) 获取信号量,本质就是给其中的计数-1(获取权利)
   	//成功立即返回,失败使用调用者进程进入睡眠状态(深度睡眠kiii -9都杀不死) ,
  	//直到可以获取信号量成功才被唤醒、返回
	void down(struct semaphore *sem);

  	//成功立即返回,失败进入可中断的睡眠状态(潜睡眠,可被ctrl+c打断)
    //可以获取信号量 + 收到信号(ctrl+c)
  	int down_interruptible(struct semaphore *sem); //关注返回值

    //失败立即返回一个错误信息,不会导致睡眠
    //可以在中断上下文中使用
 	int down_trylock(struct semaphore *sem);

	//失败进入可以kill的睡眠状态 
	int down_killable(struct semaphore *sem);     
	
	//获取信号量,指定超时时间为x
    //如果获取信号量不成功,对应的进程进入睡眠状态
    //可能因为信号量可用而被唤醒/也可能因为定时时间到而被唤醒
	int down_timeout(struct semaphore *sem, long jiffies);
	
 // 4) 执行临界区代码,访问共享资源
 
 // 5)释放信号量,本质就是给计数器+1
    void up(struct semaphore *sem);

实例

btn_drv.c:

#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/device.h>
#include <linux/cdev.h>
#include <linux/delay.h>

MODULE_LICENSE("GPL");

dev_t dev;
struct cdev btn_cdev;
struct class *cls = NULL;

int count = 1; //共享资源

spinlock_t btn_lock;
struct semaphore btn_sem;

int btn_open(struct inode *inode, struct file *filp)
{ 
    down(&btn_sem);      //3.获取信号量

    count--;             //4.执行临界区代码,访问共享资源
    if(count !=0 )       
    {
        count++;  
        /*释放信号量*/
        up(&btn_sem);
        return -EBUSY;
    }

    //msleep(1000* 20);
    //mdelay(1000*20);
   
    up(&btn_sem);          /*5.释放信号量*/
    
    return 0;
}

int btn_close(struct inode *inode, struct file *filp)
{
    down(&btn_sem);
    count++;
    up(&btn_sem);
    return 0;
}

struct file_operations btn_fops =
{
    .owner = THIS_MODULE,
    .open  = btn_open,
    .release = btn_close,
};

int __init btn_drv_init(void)
{
    /*设备号的申请注册*/
    alloc_chrdev_region(&dev, 100, 1, "mybuttons");
    /*初始化cdev*/
    cdev_init(&btn_cdev, &btn_fops);
    /*注册cdev*/
    cdev_add(&btn_cdev, dev, 1);
    /*设备文件的创建*/
    cls = class_create(THIS_MODULE, "buttons");
    device_create(cls, NULL, dev, NULL,"mybuttons");
  
    
    spin_lock_init(&btn_lock);      /*2.初始化自旋锁*/
    sema_init(&btn_sem, 1);

    return 0;
}

void __exit btn_drv_exit(void)
{
    /*销毁设备文件*/
    device_destroy(cls, dev);
    class_destroy(cls);

    /*注销cdev*/
    cdev_del(&btn_cdev);

    /*注销设备号*/
    unregister_chrdev_region(dev, 1);
}
module_init(btn_drv_init);
module_exit(btn_drv_exit);

//其他部分和操作,和自旋锁一模一样


关于 LINUX驱动 的其它文章请点击这里:     LINUX驱动

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值