linux驱动程序中的并发控制(原子操作)-43

Posted 杨斌并

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了linux驱动程序中的并发控制(原子操作)-43相关的知识,希望对你有一定的参考价值。

原子操作

整型的原子操作

  • 使对整型的int 的操作变成原子操作,要依靠一个数据类型:atomic_t。此结构体定义在 include/linux/types.h 文件中,定义如下:
typedef struct {
	int counter;
} atomic_t;

相关的api

  • #include<asm/atomic.h>
函数描述
ATOMIC_INIT(int i)定义原子变量的时候初始化
int atomic_read(atomic_t *v)读取原子变量 v 的值,并且返回
void atomic_set(atomic_t *v, int i)向 v 写入 i 值
void atomic_add(int i, atomic_t *v)给 v 加上 i 值
void atomic_sub(int i, atomic_t *v)给 v 减去 i 值
void atomic_inc(atomic_t *v)自增
void atomic_dec(atomic_t *v)自减
int atomic_dec_return(atomic_t *v)自减,并返回 v 的值
int atomic_inc_return(atomic_t *v)自增,并返回 v 的值
int atomic_sub_and_test(int i, atomic_t *v)从 v 减 i,如果结果为 0 就返回真,否则返回假
int atomic_dec_and_test(atomic_t *v)从 v 减 1,如果结果为 0 就返回真,否则返回假
int atomic_inc_and_test(atomic_t *v)给 v 加 1,如果结果为 0 就返回真,否则返回假
ATOMIC_INIT(int i)定义原子变量的时候初始化
int atomic_add_negative(int i, atomic_t *v)给 v 加 i,如果结果为负就返回真,否则返回假
atomic64_add_unless(atomic64_t *v, long a, long u)如果变量v的值不等于u,则v加a,并返回非0的值,否则v的值不变,并返回0
atomic64_inc_not_zero(atomic_t *v)如果变量v的值不等于0,则v加1,并返回非0的值,否则v的值不变,并返回0

位原子操作

  • linux 内核提供了可以用原子的方式进行操作的功能,也就是位原子操作。这种操作的操作数类型是 unsigned long。位原子操作函数就是将指定位设为0,或设为1
unsigned long value = 0;
//设置value 的第0位为1,value当前的值是1
set_bit(0,&value);
//设置value 的第2位为1,value当前的值是5
set_bit(2,&value);
函数描述
void set_bit(int nr, void *p)将 p 地址的第 nr 位置 1
void clear_bit(int nr,void *p)将 p 地址的第 nr 位清零
void change_bit(int nr, void *p)将 p 地址的第 nr 位进行翻转
int test_bit(int nr, void *p)获取 p 地址的第 nr 位的值
int test_and_set_bit(int nr, void *p)将 p 地址的第 nr 位置 1,并且返回 nr 位原来的值
int test_and_clear_bit(int nr, void *p)将 p 地址的第 nr 位清零,并且返回 nr 位原来的值
int test_and_change_bit(int nr, void *p)将 p 地址的第 nr 位翻转,并且返回 nr 位原来的值
  • atomic_test.c
#include<linux/module.h>
#include<linux/init.h>
#include<linux/kernel.h>
#include<linux/fs.h>
#include<linux/miscdevice.h>
#include<asm/uaccess.h>
#include<asm/atomic.h>
//定义设备文件的名字为atomic
#define DEVICE_NAME "atomic"
//模块传递的参数 非0 只有一个设备可以打开, 为0 可以多个进程打开这个atomic 设备
static int atom=1;
//初始化int_atomic_available 变量
static atomic_t int_atomic_available=ATOMIC_INIT(1);

static int atomic_open(struct inode *node,struct file *file){
    int ret = 0;
    if(atom){
        //atomic_dec_and_test 将int_atomic_available 减1 如果为int_atomic_available 为0 则放回1 否则返回0
        //int_atomic_available 这个值减1后不为0 则减一后 返回错误
         ret = atomic_dec_and_test(&int_atomic_available);
        if(!ret){
            //将int_atomic_available 减1
            printk("atomic_open is busy");
            atomic_inc(&int_atomic_available);
            return -EBUSY;
        }
    }
    printk("atomic dev open successfully !\\n");
    return 0;
}

static int atomic_release(struct inode *node,struct file *file){
    if(atom){
        //int_atomic_available  正常打开是 0 , 没有打开是1  减一将文件打开状态设置为初始为打开状态
        atomic_inc(&int_atomic_available);
    }
    printk("atomic dev release successfully !\\n");
    return 0;
}

static struct file_operations dev_fops={
    .owner=THIS_MODULE,
    .open=atomic_open,
    .release=atomic_release
};

static struct miscdevice misc={
    .minor=MISC_DYNAMIC_MINOR,
    .name=DEVICE_NAME,
    .fops=&dev_fops
};

static int __init atomic_init(void){
    int ret=misc_register(&misc);
    if(ret < 0 ){
        printk("atomic_init is error");
        return -1;
    }
    printk("atomic_init_success\\n");
    return ret;
}

static void __exit atomic_exit(void){
    printk("atomic_exit_success\\n");
    misc_deregister(&misc);
}

module_init(atomic_init);
module_exit(atomic_exit);
module_param(atom,int,S_IRUGO|S_IWUSR);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("binbing.Yang");
  • app.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

int main(int argc, char *argv[]){
    int handler=open("/dev/atomic",0);
    printf("handler : %d\\n",handler);

    if(handler>0){
        //getchar();让程序停留在这一步,直到它从键盘接收到消息
        getchar();
        close(handler);
    }else{
        printf("errno:%d\\n",errno);
    }
    return 0;
}

insmod day1_proc.ko atom=0 //多设终端访问
insmod day1_proc.ko atom=0 //只能一个终端访问

以上是关于linux驱动程序中的并发控制(原子操作)-43的主要内容,如果未能解决你的问题,请参考以下文章

linux驱动程序中的并发控制(自旋锁)-44

linux驱动程序中的并发控制-2(自旋锁)-44

Linux 设备驱动的并发控制 学习笔记

设备驱动中的并发控制

Linux驱动设备中的并发控制

Linux设备驱动之并发控制