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

本文详细介绍了Linux内核中的原子操作,包括atomic_t类型的使用以及相关API,如atomic_read、atomic_set、atomic_add等,用于保证整型变量在多线程环境下的操作原子性。此外,还讲解了位原子操作,如set_bit、clear_bit等,用于原子地修改内存中的位。通过示例代码展示了如何在设备驱动中应用这些原子操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原子操作

整型的原子操作

  • 使对整型的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 //只能一个终端访问

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值