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

杨斌并 杨斌并     2022-12-13     251

关键词:

原子操作

整型的原子操作

  • 使对整型的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驱动程序中的并发控制(自旋锁)-44(代码片段)

自旋锁(spinlock)简介原子锁和自旋锁的使用范围原子操作是一种很好的避免竞态的方式,使用非常简单。但在某些方面却显得过于简单。例如,有很多数据需要被格式化,被添加到某些数据结构中,然后... 查看详情

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

自旋锁(spinlock)简介原子锁和自旋锁的使用范围原子操作是一种很好的避免竞态的方式,使用非常简单。但在某些方面却显得过于简单。例如,有很多数据需要被格式化,被添加到某些数据结构中,然后... 查看详情

设备驱动中的并发控制

在为操作系统编写驱动设备时,因为涉及到中断、多任务和多处理器SMP的处理,所以内核提供了诸如中断屏蔽、原子操作、信号量、完成量等几种并发控制机制,对公用资源进行保护。下文将分别予以阐述。0、中断中断屏蔽使... 查看详情

linux设备驱动的并发控制学习笔记(代码片段)

文章目录并发和竞态编译乱序和执行乱序并发控制机制中断屏蔽原子操作整型原子操作位原子操作自旋锁自旋锁的使用读写自旋锁顺序锁读-复制-更新信号量互斥体完成量并发和竞态并发:多个执行单元同时、并行被执行。... 查看详情

linux驱动开发原子操作自旋锁信号量互斥体(代码片段)

...片内存区域的情况,多个任务可能会相互覆盖掉内存中的数据,造成内存数据混乱。Linux系统并发主要原因多线程并发访问抢占式并发访问中断程序并发访问多核间并发访问通常需要对全局变量、设备结构体这些共享资源... 查看详情

实战java高并发程序设计5让普通变量也享受原子操作

【实战Java高并发程序设计1】Java中的指针:Unsafe类【实战Java高并发程序设计2】无锁的对象引用:AtomicReference【实战Java高并发程序设计3】带有时间戳的对象引用:AtomicStampedReference【实战Java高并发程序设计4】数组也能无锁:Atomi... 查看详情

java并发编程的艺术--原子操作类和并发工具类(第七八章)(代码片段)

...子更新字段类常用类1.4.2、AtomicIntegerFieldUpdater的使用2、并发工具类2.1、CountDownLatch2.1.1、简介2.1.2、CountDownLatch的使用2.1.3、应用场景2.2、CyclicBarrier2.2.1、简介2.2.2、CyclicBarrier的使用2.2.3、应用场景2.2.4、CyclicBarrier和CountDownLatch的区... 查看详情

linux设备驱动基础01之并发与竞态(代码片段)

...问同一片内存区域的情况,可能会相互覆盖这段内存中的数据,最终造成内存数据混乱,严重的话会导致系统崩溃。驱动开发中要注意对共享资源的保护,需要管理对共享资源的并发访问。Linux系统产生并发访问... 查看详情

linux设备驱动中的并发

参考技术A并发就是多个执行单元或多个进程并行执行,而这多个执行单元对资源进行共享,比如访问同一个变量或同一个硬件资源,这个时候就很容易出现竞态(说简单点就是竞争同一个”女朋友”)。为了处理并发带来的问题,... 查看详情

linux驱动之并发与竞争(代码片段)

...同一片内存区域,这些任务可能会相互覆盖这段内存中的数据,造成内存数据混乱。针对这个问题必须要做处理,严重的话可能会导致系统崩溃。linux存在以下并发访问:①、多线程并发访问,Linux是多任务(线程)的... 查看详情

linux并发与竞争(原子操作自旋锁信号量互斥体)(代码片段)

目录并发与竞争原子操作原子操作简介原子整形操作API函数原子位操作API函数自旋锁自旋锁简介自旋锁API函数其他类型的锁自旋锁使用注意事项信号量信号量简介信号量API函数互斥体互斥体简介互斥体API函数Linux是一个多任务操... 查看详情

linux并发与竞争实验(代码片段)

...试实验程序编写运行测试在上一章中我们学习了Linux下的并发与竞争,并且学习了四种常用的处理并发和竞争的机制:原子操作、自旋锁、信号量和互斥体。本章我们就通过四个实验来学习如何在驱动中使用这四种机制。... 查看详情

linux驱动程序中的并发控制-4(顺序自旋锁)-46(代码片段)

顺序自旋锁顺序锁与读写自旋锁类似,只是为写锁赋予了更高的权限。在读写自旋锁中,读锁和写锁的优先级是相同的。当读锁获取读自旋锁时,写锁必须等待,直到临界区的代码执行完成,并释放读自旋锁... 查看详情

linux驱动程序中的并发控制-4(顺序自旋锁)-46(代码片段)

顺序自旋锁顺序锁与读写自旋锁类似,只是为写锁赋予了更高的权限。在读写自旋锁中,读锁和写锁的优先级是相同的。当读锁获取读自旋锁时,写锁必须等待,直到临界区的代码执行完成,并释放读自旋锁... 查看详情

linux操作系统中的引导程序与服务控制

...导 开机自检  服务器主机开机以后,将根据主板BIOS中的设置对CPU、内存、显卡、键盘等设备进行初步检测,检测成功 查看详情

并发编程的缺点?

1、Java中的线程对应是操作系统级别的线程,线程数量控制不好,频繁的创建、销毁线程和线程间的切换,比较消耗内存和时间。2、容易带来线程安全问题。如线程的可见性、有序性、原子性问题,会导致程序出现的结果与预期... 查看详情

volatile,从jvm的层面解释并发(代码片段)

...种解决方式2.2.1总线锁2.2.2缓存一致性协议三、并发编程中的三个概念3.1原子性3.1.1原子性定义3.1.2原子性举例3.2可见性3.2.1可见性定义3.2.2可见性举例3.3有序性3.3.1有序性定义3.3.2有序性举例(单线程下指令重排不会造成线程安全问... 查看详情

volatile,从jvm的层面解释并发(代码片段)

...种解决方式2.2.1总线锁2.2.2缓存一致性协议三、并发编程中的三个概念3.1原子性3.1.1原子性定义3.1.2原子性举例3.2可见性3.2.1可见性定义3.2.2可见性举例3.3有序性3.3.1有序性定义3.3.2有序性举例(单线程下指令重排不会造成线程安全问... 查看详情