Linux内核并发与竞争-原子操作

news2024/10/2 16:16:08

一.原子操作的概念

首先看一下原子操作,原子操作就是指不能再进一步分割的操作,一般原子操作用于变量或者位操作。假如现在要对无符号整形变量 a 赋值,值为 3,对于 C 语言来讲很简单,直接就是: a=3

但是 C 语言要先编译为成汇编指令, ARM 架构不支持直接对寄存器进行读写操作,比如要借助寄存器 R0、 R1 等来完成赋值操作。假设变量 a 的地址为 0X3000000,“a=3”这一行 C语言可能会被编译为如下所示的汇编代码:

ldr r0, =0X30000000 /* 变量 a 地址 */

ldr r1, = 3 /* 要写入的值 */

str r1, [r0] /* 将 3 写入到 a 变量中 */

示例代码 只是一个简单的举例说明,实际的结果要比示例代码复杂的多。从上述代码可以看出, C 语言里面简简单单的一句“a=3”,编译成汇编文件以后变成了 3 句,那么程序在执行的时候肯定是按照示例代码 中的汇编语句一条一条的执行。假设现在线程 A要向 a 变量写入 10 这个值,而线程 B 也要向 a 变量写入 20 这个值,我们理想中的执行顺序如图 所示:

按照图所示的流程,确实可以实现线程 A 将 a 变量设置为 10,线程 B 将 a 变量设置为 20。但是实际上的执行流程可能如下图所示:

按照图 所示的流程,线程 A 最终将变量 a 设置为了 20,而并不是要求的 10!线程B 没有问题。这就是一个最简单的设置变量值的并发与竞争的例子,要解决这个问题就要保证示例代码 中的三行汇编指令作为一个整体运行,也就是作为一个原子存在。 Linux 内核提供了一组原子操作 API 函数来完成此功能, Linux 内核提供了两组原子操作 API 函数,一组是对整形变量进行操作的,一组是对位进行操作的,我们接下来看一下这些 API 函数。

二.原子操作的函数介绍

1.原子整形操作API函数

Linux 内核定义了叫做 atomic_t 的结构体来完成整形数据的原子操作,在使用中用原子变量来代替整形变量,此结构体定义在 include/linux/types.h 文件中,定义如下:

typedef struct {
    int counter;
} atomic_t;

2.原子位操作API函数

三.实验

我们这个还是之前的思路,如果不牵扯到硬件操作,那么我们就在ubuntu pc做实验,这样高效,比较方便

driver

#include <linux/types.h>
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/mm.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/module.h>
#include <linux/device.h>



#define CHRDEVBASE_MAJOR    200
uint8_t kernel_buffer[1024] = {0};
static struct class *hello_class;
atomic_t lock;

static int hello_world_open(struct inode * inode, struct file * file)
{
    int count;
    printk("hello_world_open\r\n");
    
    count = atomic_read(&lock);
    printk("count:%d\r\n",count);
    if(count)
    {
        printk("already open ,return fail\r\n");
    }
    else
        atomic_inc(&lock);
    
    return 0;
}

static int hello_world_release (struct inode * inode, struct file * file)
{
    printk("hello_world_release\r\n");
    atomic_dec(&lock);
    return 0;
}


static const struct file_operations hello_world_fops = {
    .owner        = THIS_MODULE,
    .open        = hello_world_open,
    .release = hello_world_release,
    .read        = NULL,
    .write    = NULL,
};


static int __init hello_driver_init(void)
{
    int ret;
    printk("hello_driver_init\r\n");
    
    atomic_set(&lock,0);
    

    ret = register_chrdev(CHRDEVBASE_MAJOR,"hello_driver",&hello_world_fops);

    hello_class = class_create(THIS_MODULE,"hello_class");

    device_create(hello_class,NULL,MKDEV(CHRDEVBASE_MAJOR,0),NULL,"hello"); /* /dev/hello */

    return 0;
}

static void __exit hello_driver_cleanup(void)
{
    printk("hello_driver_cleanup\r\n");
    device_destroy(hello_class,MKDEV(CHRDEVBASE_MAJOR,0));
    class_destroy(hello_class);
    unregister_chrdev(CHRDEVBASE_MAJOR,"hello_driver");
    
}


module_init(hello_driver_init);
module_exit(hello_driver_cleanup);
MODULE_LICENSE("GPL");


app

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>


/* mknod /dev/chrdevbase c 200 0 */

uint8_t buffer[512] = {0};

int main(int argc, char *argv[])
{
    int fd;
    int ret;
    
    fd  = open(argv[1], O_RDWR);

    printf("sleep\r\n");
    sleep(60);
    printf("wake up\r\n");
    
    close(fd);

    
}

Makefile

KERNELDIR := /lib/modules/$(shell uname -r)/build
CURRENT_PATH := $(shell pwd)
obj-m := atomic_driver.o

build: kernel_modules

kernel_modules:
    $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) modules
    $(CROSS_COMPILE)gcc -o test_app test_app.c
clean:
    $(MAKE) -C $(KERNELDIR) M=$(CURRENT_PATH) clean
    rm -rf test_app

参考:

1.【韦东山】嵌入式Linux应用开发完全手册V4.0_韦东山全系列视频文档-IMX6ULL开发板.docx

2.【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.4.pdf

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/337844.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

机器学习基本原理总结

本文大部分内容参考《深度学习》书籍&#xff0c;从中抽取重要的知识点&#xff0c;并对部分概念和原理加以自己的总结&#xff0c;适合当作原书的补充资料阅读&#xff0c;也可当作快速阅览机器学习原理基础知识的参考资料。 前言 深度学习是机器学习的一个特定分支。我们要想…

Elasticsearch bucket_script、bucket_selector、bucket_sort 区别和应用场景?

1、实战问题POST test-002/_bulk {"index":{"_id":1}} {"name": "张三","city": "beijing"} {"index":{"_id":2}} {"name": "李四","city": "beijing&qu…

简信CRM:医疗健康行业数字化解决方案

随着社会群体健康意识提升、用户消费习惯变化、新冠疫情冲击等因素&#xff0c;人们对于个人和公共安全健康问题就越发重视&#xff0c;而且已经逐渐从对“病”的被动治疗转变为对“健康”的主动管理&#xff0c;医疗健康行业呈现出一片火热的趋势。但医疗健康行业的情况比较复…

idekCTF 2022 比赛复现

Readme 首先 []byte 是 go 语言里面的一个索引&#xff0c;比如&#xff1a; package mainimport "fmt"func main() {var str string "hello"var randomData []byte []byte(str)fmt.Println(randomData[0:]) //[104 101 108 108 111] }上面这串代码会从…

Java程序运行机制

Java语言既具有编译型语言的特征&#xff0c;又具有解释型语言的特征&#xff0c;Java程序要经过先编译后解释两个阶段。高级语言的运行机制&#x1f4cd;编译型语言使用专门的编译器&#xff0c;针对特定的平台&#xff08;移植性差&#xff09;&#xff0c;将高级语言的源代码…

情人节有哪些数码好物值得送礼?情人节实用性强的数码好物推荐

转瞬间&#xff0c;情人节快到了&#xff0c;大家还在为送什么礼物而烦恼&#xff1f;在这个以科技为主的时代&#xff0c;人们正在享受着科技带来的便利&#xff0c;其中&#xff0c;数码产品也成为了日常生活中必不可少的存在。接下来&#xff0c;我来给大家推荐几款比较实用…

大数据框架之Hadoop:入门(四)Hadoop运行模式

Hadoop运行模式包括&#xff1a;本地模式、伪分布式模式以及完全分布式模式。 Hadoop官方网站&#xff1a;http://hadoop.apache.org/ 4.1本地运行模式 4.1.1官方Grep案例 1.创建在hadoop文件夹下面创建一个input文件夹 [roothdp101 hadoop]# mkdir input2.将Hadoop的xml配…

SpringBoot整合Druid数据源(实行监控功能)

在上篇文章中分析了数据连接池&#xff08;Durid&#xff09;在应用中可以做到资源重用&#xff0c;提升系统响应速度&#xff0c;避免数据库连接遗漏。它除了是一个高性能数据库连接池之外&#xff0c;更是一个自带监控的数据库连接池 JDDC与Druid 1Druid是什么 Apache Drui…

tui-swipe-action组件上的按钮点击后有阴影的解决方法

大家好,我是雄雄,欢迎关注微信公众号:雄雄的小课堂。 目录 前言问题描述问题解决前言 一直未敢涉足电商领域,总觉得这里面的道道很多,又是支付、又是物流的,还涉及到金钱,所以我们所做的项目,一直都是XXXX管理系统,XXX考核系统,移动端的也是,XX健康管理平台…… 但…

SLAM中坐标轴旋转及ros的接口解释

读完几个loam算法&#xff0c;满篇的坐标轴旋转&#xff0c;还是手写的(作者&#xff0c;用eigen写不好嘛。。。)&#xff0c;我滴天适应了好久…&#xff0c;今天就总结一下坐标轴旋转问题。 一、首先&#xff0c;我们看一下ros中关于欧拉角旋转的函数&#xff1a;setRPY、set…

C++展开模板参数包、函数参数包-(lambda+折叠表达式)

开门见山 以下代码可展开模板参数包和展开函数参数包。 // lambda折叠表达式(需C17) #include <iostream> using namespace std;// 1.展开模板参数包 template<typename ...T> void Func1() {([]() {cout << typeid(T).name() << endl;}(), ...);// …

姿态估计端到端新方案 | DirectMHP:用于全范围角度2D多人头部姿势估计

前言 现有的头部姿势估计主要集中在具有预先检测到的正面头部的单个人&#xff0c;这依赖于单独训练的面部检测器&#xff0c;不能很好地泛化到完整的视点。在本文中&#xff0c;作者关注全范围 MPHPE 问题&#xff0c;并提出了一个名为 DirectMHP 的直接端到端简单基线&#x…

怎么给笔记本电脑外接两台显示器?

我们在办公室会看见不少同事的电脑不止一台显示器&#xff0c;多屏确实可以提高工作效率。有的游戏党也会选择给电脑外接显示器&#xff0c;带来绝佳的体验。 不过要怎么把将外部显示器连接到笔记本电脑上&#xff1f;驱动人生在这里教给大家给笔记本外接显示器的做法。 一、…

TensorFlow CNN 卷积神经网络实现人脸性别检测 完整教程 附完整代码

本文主要是实现了根据人脸识别性别的卷积神经网络,并对卷积过程中的提取特征进行了可视化.

HydroD 实用教程(二)有限元模型

目 录一、前言二、模型种类三、单元类型四、FEM文件五、参考文献一、前言 SESAM &#xff08;Super Element Structure Analysis Module&#xff09;是由挪威船级社&#xff08;DNV-GL&#xff09;开发的一款有限元分析&#xff08;FEA&#xff09;系统&#xff0c;它以 GeniE、…

【Linux command 09】tcpdump 命令

tcp一款sniffer工具&#xff0c;是Linux上的抓包工具&#xff0c;嗅探器语法tcpdump (选项)选项-c&#xff1a; 指定要抓取的包数量。注意&#xff0c;是最终要获取这么多个包。例如&#xff0c;指定"-c 10"将获取10个包&#xff0c;但可能已经处理了100个包&#xf…

激光slam学习笔记2--激光点云数据结构特点可视化查看

背景&#xff1a;不同厂商的激光点云结果存在一定差异&#xff0c;比如有些只有xyz&#xff0c;有些包含其他&#xff0c;如反光率、时间戳、ring等。如何快速判断是个值得学习的点 概要&#xff1a;对于rosbag类型的激光点云&#xff0c;介绍使用rviz快速查看点云结构特点 如…

JavaWeb--MySQL高级

MySQL高级1 约束1.1 概念1.2 分类1.3 非空约束1.4 唯一约束1.5 主键约束1.6 默认约束1.7 检查约束1.8 外键约束1.8.1 概述1.8.2 语法2 数据库设计2.1 数据库设计简介2.2 表关系(一对多)2.3 表关系(多对多)2.4 表关系(一对一)3 多表查询3.1 内连接查询3.2 外连接查询3.3 子查询3…

技能树基础——17四平方和(拉格朗日定理,嵌套循环)

题目&#xff1a;四平方和定理&#xff0c;又称为拉格朗日定理&#xff1a;每个正整数都可以表示为至多4个正整数的平方和。如果把0包括进去&#xff0c;就正好可以表示为4个数的平方和。比如&#xff1a;5 0^ 2 0^ 2 1^ 2 2^27 1^ 2 1^ 2 1^ 2 2^2 &#xff08;^符号表…

微服务项目【服务调用分布式session共享】

nginx动静分离 第1步&#xff1a;通过SwitchHosts新增二级域名&#xff1a;images.zmall.com 第2步&#xff1a;将本次项目的所有静态资源js/css/images复制到nginx中的html目录下 第3步&#xff1a;在nginx的核心配置文件nginx.conf中新增二级域名images.zmall.com访问映射…