6410之同步互斥阻塞

同步互斥:

目的:在同一时间只有一个应用程序打开设备节点/dev/buttons。linux是一个多任务系统,在读写同一个节点的时候,可能会有多个应用程序。这就需要进行同步操作,保证应用程序的完整执行。

方法1:在linux中使用原子操作:

1. 原子操作
原子操作指的是在执行过程中不会被别的代码路径所中断的操作。
常用原子操作函数举例:
atomic_t v = ATOMIC_INIT(0);     //定义原子变量v并初始化为0
atomic_read(atomic_t *v);        //返回原子变量的值
void atomic_inc(atomic_t *v);    //原子变量增加1
void atomic_dec(atomic_t *v);    //原子变量减少1
int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。


基于之前的代码,修改如下:

static atomic_t canopen = ATOMIC_INIT(1); 


static int buttons_drv_open(struct inode *inode, struct file *file)
{
if(!atomic_dec_and_test(&canopen)){
atomic_inc(&canopen);
return -EBUSY;
}

printk("buttons_drv_open \n");


request_irq(IRQ_EINT(0),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD1", &pins_desc[0]);
request_irq(IRQ_EINT(1),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD2", &pins_desc[1]);
request_irq(IRQ_EINT(2),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD3", &pins_desc[2]);
request_irq(IRQ_EINT(3),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD4", &pins_desc[3]);

return 0;
}


在释放的时候:

int buttons_drv_release(struct inode *inode, struct file *file)
{
atomic_inc(&canopen);
free_irq(IRQ_EINT(0),&pins_desc[0]);
free_irq(IRQ_EINT(1),&pins_desc[1]);
free_irq(IRQ_EINT(2),&pins_desc[2]);
free_irq(IRQ_EINT(3),&pins_desc[3]);


return 0;
}

现象如下:



方法2:信号量:

信号量(semaphore)是用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。当获取不到信号量时,进程进入休眠等待状态

定义信号量
struct semaphore sem;
初始化信号量
void sema_init (struct semaphore *sem, int val);
void init_MUTEX(struct semaphore *sem);//初始化为0

static DECLARE_MUTEX(button_lock);     //定义互斥锁

获得信号量
void down(struct semaphore * sem);
int down_interruptible(struct semaphore * sem);
int down_trylock(struct semaphore * sem);
释放信号量
void up(struct semaphore * sem);

代码修改如下:

static DECLARE_MUTEX(button_lock);


static int buttons_drv_open(struct inode *inode, struct file *file)
{
down(&button_lock);
printk("buttons_drv_open \n");


request_irq(IRQ_EINT(0),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD1", &pins_desc[0]);
request_irq(IRQ_EINT(1),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD2", &pins_desc[1]);
request_irq(IRQ_EINT(2),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD3", &pins_desc[2]);
request_irq(IRQ_EINT(3),button_irq_handle,IRQF_TRIGGER_FALLING|IRQF_TRIGGER_RISING, "PAD4", &pins_desc[3]);


return 0;
}


int buttons_drv_release(struct inode *inode, struct file *file)
{
free_irq(IRQ_EINT(0),&pins_desc[0]);
free_irq(IRQ_EINT(1),&pins_desc[1]);
free_irq(IRQ_EINT(2),&pins_desc[2]);
free_irq(IRQ_EINT(3),&pins_desc[3]);
up(&button_lock);

return 0;
}

现象如下:

执行两次./synctest &

ps命令:


其中一个会进行休眠,当前面的synctest结束后,后面的synctest会立即从休眠中唤醒立即执行。


阻塞与非阻塞:

阻塞操作
是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再进行操作。被挂起的进程进入休眠状态,被从调度器的运行队列移走,直到等待的条件被满足。

非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直至可以进行操作为止。
fd = open("...", O_RDWR | O_NONBLOCK);


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值