所有的热爱都要不遗余力,真正喜欢它便给它更高的优先级,和更多的时间吧!
关于 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驱动