当设备被一个程序打开时,存在被另一个程序打开的可能,如果两个或多个程序同时对设备文件进行写操作,这就是说我们的设备资源同时被多个进程使用,对共享资源(硬件资源、和软件上的全局变量、静态变量等)的访问则很容易导致竞态。
对于竟态问题有不同的处理方式,比如信号量,自旋锁等。
但是当共享的资源只是一个简单的整数,这时候我们如果利用完整的锁机制会是一种浪费,这种情况下一般使用原子变量来处理。
原子的整形变量为atomic_t,在头文件<asm/atomic.h>中定义
原子变量的相关操作函数如下
1)atomic_t v = ATOMIC_INIT(0); //定义原子变量v并初始化为0
2)atomic_read(atomic_t *v); //返回原子变量的值
3)void atomic_inc(atomic_t *v); //原子变量增加1
4)void atomic_dec(atomic_t *v); //原子变量减少1
5)int atomic_dec_and_test(atomic_t *v); //自减操作后测试其是否为0,为0则返回true,否则返回false。
除了以上函数之外的其他函数可以自行搜索
atomic_t数据项只能通过上诉的函数进行操作,如果将atomic_t变量传递给需要整型变量的参数,会导致编译出错!!
(1)创建原子变量
atomic_t open = ATOMIC_INIT(1)
创建原子变量open并且赋值为1。也可以在编译时利用ATMOIC_INIT宏来初始化原子变量的值。
(2)原子变量读取、计算、判断
if(!atomic_dec_and_test(&open))
{
atomic_inc(&open);
return -EBUSY
}
在open()函数里放入上述语句。则在某个设备打开后open - 1 = 0,因此函数返回true,从而if不成立。这个时候能够正常打开驱动。
设备A调用了驱动程序后open - 1 = 0,若这个时候设备B也想要调用驱动程序,open - 1 = -1。则函数返回false,因此if成立,open + 1 = 0之后返回-EBUSY。此时设备B无法运行,这样就能防止两个设备同时运行。
atomic_dec_and_test()函数一旦运行则不会被打断,因此不存在设备A读取了open变量为1之后,被另一个设备B中断,使得设备B读取的open也为1,从而导致两个设备都能正常运行,导致竞态。这也是使用原子变量而不是使用普通变量的原因。
(3)release函数添加
在release函数中添加以下语句
atomic_inc(&open);
测试程序:
int main(int argc,char **argv)
{
int oflag;
unsigned int val=0;
fd=open("/dev/buttons",O_RDWR);
if(fd<0)
{
printf("can't open, fd=%d\n",fd);
return -1;
}
while(1)
{
read( fd, &ret, 1); //读取驱动层数据
printf("key_vale=0X%x\r\n",ret);
}
return 0;
}