字符设备驱动程序之同步互斥阻塞

   这一节要达到的目的---同一时刻,只能要一个app 打开 /dev/keys 设备文件。
一个程序要去访问一个变量的值,其实分为3步:
① 读出;②修改;③写回 。 这3步当中就存在被打断的可能。
下面来介绍几种不会被打断的方法:
1. 原子操作
 原子操作指在执行的过程中不会被别的代码所中断的操作。
 常用的原子操作函数有:
atomic_t  v=ATCMIC_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.

2. 信号量
信号量(semaphore)--用于保护临界区的一种常用方法,只有得到信号量的进程才能执行临界区代码。当获取不到信号量时,进程进入休眠等待状态。
定义信号量
struct semaphore sem;
初始化信号量
void  sema_init(struct  semaphore *sem, int val);
void  init_MUTEX(struct  semaphore *sem);   //初始化为0
获取信号量
void  down(struct  semaphore * sem);
int down_interruptible(struct  semaphore *sem);
int down_trylock(struct semaphore *sem);
释放信号量
void up(struct semaphore *sem);  //释放信号量之后,如果有别的app在等待信号量,则会被唤醒
3.阻塞 与 非阻塞操作
阻塞是指在执行设备操作时若不能获得资源则挂起进程,直到满足可操作的条件后再执行操作。
被挂起的进程进入休眠状态,被从调试器的运行队列移走,直到等待的条件被满足。

非阻塞操作
进程在不能进行设备操作时并不挂起,它或者放弃,或者不停地查询,直到可以进行操作为止。
fd=open("...",O_RDWR | O_NONBLOCK);  
下面来看下驱动程序怎么改:
1. 定义原子操作或信号量
//static atomic_t canopen = ATOMIC_INIT(1);     //定义原子变量并初始化为1
static DECLARE_MUTEX(button_lock);     //定义互斥锁
2. 打开的时候进行信号量操作
static int sixth_drv_open(struct inode *inode, struct file *file)
{
#if 0 
      if (!atomic_dec_and_test(&canopen))  //原子操作的方法
      {
            atomic_inc(&canopen);
            return -EBUSY;
      }
#endif        
      if (file->f_flags & O_NONBLOCK)
      {
            if (down_trylock(&button_lock))
                  return -EBUSY;
      }
      else
      {
            /* 获取信号量 */
            down(&button_lock);
      }
      /* 配置GPF0,2为输入引脚 */
      /* 配置GPG3,11为输入引脚 */
      request_irq(IRQ_EINT0,  buttons_irq, IRQT_BOTHEDGE, "S2", &pins_desc[0]);
      request_irq(IRQ_EINT2,  buttons_irq, IRQT_BOTHEDGE, "S3", &pins_desc[1]);
      request_irq(IRQ_EINT11, buttons_irq, IRQT_BOTHEDGE, "S4", &pins_desc[2]);
      request_irq(IRQ_EINT19, buttons_irq, IRQT_BOTHEDGE, "S5", &pins_desc[3]);     
      return 0;
}
3. 关闭时 释放信号量
int sixth_drv_close(struct inode *inode, struct file *file)
{
      //atomic_inc(&canopen);
      free_irq(IRQ_EINT0, &pins_desc[0]);
      free_irq(IRQ_EINT2, &pins_desc[1]);
      free_irq(IRQ_EINT11, &pins_desc[2]);
      free_irq(IRQ_EINT19, &pins_desc[3]);
      up(&button_lock);
      return 0;
}
下面来看看应用程序怎么写:
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include <poll.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
int fd;
void my_signal_fun(int signum)
{
	unsigned char key_val;
	read(fd, &key_val, 1);
	printf("key_val: 0x%x\n", key_val);
}
int main(int argc, char **argv)
{
	unsigned char key_val;
	int ret;
	int Oflags;
	//signal(SIGIO, my_signal_fun);	
	fd = open("/dev/buttons", O_RDWR | O_NONBLOCK);
	if (fd < 0)
	{
		printf("can't open!\n");
		return -1;
	}
	//fcntl(fd, F_SETOWN, getpid());	
	//Oflags = fcntl(fd, F_GETFL); 	
	//fcntl(fd, F_SETFL, Oflags | FASYNC);
	while (1)
	{
		ret = read(fd, &key_val, 1);
		printf("key_val: 0x%x, ret = %d\n", key_val, ret);
		sleep(5);
	}	
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值