linux 原子操作

首先是为什么要有 原子操作

网上的截图:

不能从C语言来看,要从汇编来看

但是实际的情况有可能是这样。

A进程没有得到想要的结果。

然后是 原子操作的 底层实现

最终会是这段代码,当然只是一个 加一的操作。

static inline void atomic_add(int i, atomic_t *v)                      
{                                                                      
        unsigned long tmp;                                             
        int result;                                                    
                                                                       
        prefetchw(&v->counter);                                        
        __asm__ __volatile__("@ atomic_add "\n"                  @@后是注释            
"1:     ldrex   %0, [%3]\n"                                             
"       add     %0, %0, %4\n"                                  
"       strex   %1, %0, [%3]\n"                                        
"       teq     %1, #0\n"                                              
"       bne     1b"                                                    
        : "=&r" (result), "=&r" (tmp), "+Qo" (v->counter)         @输出部分       
        : "r" (&v->counter), "Ir" (i)                             @输入部分   
        : "cc");                                                  @破坏描述部分               
}  

这里需要知道两个命令。

ldrex,strex

这个例子很好。

也就是说, 汇编上,只有, strex 才是真正的原子,ldrex 就是先到先得了。因为这只是读,但是写就不一样了。

我的疑问: 如果进程没有获得原子变量怎么办,是休眠还是返回,还是空转。

然后是一个 关于 atomic 使用的例子。

#include <linux/module.h>
#include <linux/cdev.h>
#include <linux/fs.h>

#define OK   (0)
#define ERROR  (-1)

/* 原子变量 */
static atomic_t canopen = ATOMIC_INIT(1);

int hello_open(struct inode *p, struct file *f)
{
    /*自减1并判断是否位0 */
    if(!atomic_dec_and_test(&canopen)){
        /* 恢复原始值 */
        atomic_inc(&canopen);
        printk("device busy,hello_open failed");
        return ERROR;
    }
    printk("hello_open\n");
    return 0;
}

ssize_t hello_write(struct file *f, const char __user *u, size_t s, loff_t *l)
{
    printk("hello_write\n");
    return 0;
}

ssize_t hello_read(struct file *f, char __user *u, size_t s, loff_t *l)
{
    printk("hello_read\n");
    return 0;
}

int hello_close(struct inode *inode, struct file *file)
{
    /* 恢复原始值 */
// 这里问什么要 增加以下呢? 因为 if(!atomic_dec_and_test(&canopen)) 在判断的时候也是执行的。
    atomic_inc(&canopen);
    return 0;
}

struct file_operations hello_fops = {
    .owner   =   THIS_MODULE,
    .open    =   hello_open,
    .read    =   hello_read,
    .write   =   hello_write,
    .release =   hello_close,
};

dev_t devid;                      // 起始设备编号
struct cdev hello_cdev;          // 保存操作结构体的字符设备 
struct class *hello_cls;

int hello_init(void)
{
    
    /* 动态分配字符设备: (major,0) */
    if(OK == alloc_chrdev_region(&devid, 0, 1,"hello")){   // ls /proc/devices看到的名字
        printk("register_chrdev_region ok\n");
    }else {
        printk("register_chrdev_region error\n");
        return ERROR;
    }
    
     cdev_init(&hello_cdev, &hello_fops);
     cdev_add(&hello_cdev, devid, 1);


    /* 创建类,它会在sys目录下创建/sys/class/hello这个类  */
     hello_cls = class_create(THIS_MODULE, "hello");
     if(IS_ERR(hello_cls)){
         printk("can't create class\n");
         return ERROR;
     }
    /* 在/sys/class/hello下创建hellos设备,然后mdev通过这个自动创建/dev/hello这个设备节点 */
     device_create(hello_cls, NULL, devid, NULL, "hello"); 

     return 0;
}

void __exit hello_exit(void)
{
    printk("hello driver exit\n");
    /* 注销类、以及类设备 /sys/class/hello会被移除*/
    device_destroy(hello_cls, devid);
    class_destroy(hello_cls);

    cdev_del(&hello_cdev);
    unregister_chrdev_region(devid, 1);
    return;
}


module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");

需要注意的地方:  原子操作 是没有 阻塞与非阻塞的概念的。就是一个 if 判断,原子变量的值, 如果值 不符合要求 就直接 返回 了。

我的疑问: 我们知道 open 是以 阻塞方式打开的,也就是 说应用的阻塞的关键字没有起到作用吗?

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

从0到1构建 UniApp + Vue3 + TypeScript 移动端跨平台开源脚手架

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f343; vue-uniapp-template &#x1f33a; 仓库主页&#xff1a; GitCode&#x1f4ab; Gitee &#x1f…

解析日期、编码

解析日期 这里指的是将字符串或者object类型的日期&#xff0c;转换成panda或python的日期类型。 主要的是dtype的变化&#xff1a;object / str —> datetime64[ns] # modules well use import pandas as pd import numpy as np import seaborn as sns import datetime# …

swiper默认显示三个,中间放大且显示全部图片两边显示部分图片

先上效果图 template <template><div><div class"swiper-content"><div class"swiper-container"><div class"swiper-wrapper"><div class"swiper-slide"><img src"../../assets/images/…

【每日刷题】Day146

【每日刷题】Day146 &#x1f955;个人主页&#xff1a;开敲&#x1f349; &#x1f525;所属专栏&#xff1a;每日刷题&#x1f34d; &#x1f33c;文章目录&#x1f33c; 1. mari和shiny 2. 组队竞赛__牛客网 3. 删除相邻数字的最大分数_牛客题霸_牛客网 1. mari和shiny /…

Resnet搭建介绍及代码撰写详解(总结6)

可以从本人以前的文章中可以看出作者以前从事的是嵌入式控制方面相关的工作&#xff0c;是一个机器视觉小白&#xff0c;之所以开始入门机器视觉的学习主要是一个idea&#xff0c;想把机器视觉与控制相融合未来做一点小东西。废话不多说开始正题。&#xff08;如有侵权立即删稿…

compose.material3 中的DatePicker在 desktop 平台同样可以适用

引入 implementation(compose.material3) 添加触发 OptIn(ExperimentalMaterial3Api::class)Composableprivate fun BasicDateUnit(label: String, selectedDateStr: MutableState<String>) {var showDatePicker by remember { mutableStateOf(false) }var selectedDate…

115页PPT集团管控模型与企业实践5D

01 115页PPT集团管控模型与企业实践5D “5D1C”模型是一种集团管控框架&#xff0c;它将集团管控的主要任务划分为五个方面以及一个核心&#xff0c;即战略&#xff08;Strategy&#xff09;、组织&#xff08;Organization&#xff09;、决策&#xff08;Decision&#xff09…

创客匠人老蒋:创始人自己做服务,才有市场敏感度

大家好&#xff0c;我是老蒋。上周&#xff0c;老蒋对话标杆直播间第70期邀请到了【华雨婚姻课堂】平台创始人大雨老师&#xff0c;请他聊了聊关于如何有效提高用户粘性&#xff1f;如何深度联动用户&#xff0c;提升高客单转化&#xff1f;也分享了短视频和直播两大赛道关于内…

fpga系列 HDL: 竞争和冒险 02

竞争和冒险 在 Verilog 设计中&#xff0c;竞争&#xff08;race conditions&#xff09;和冒险&#xff08;hazards&#xff09;是数字电路设计中不期望出现的现象&#xff0c;它们会影响电路的正确性。了解并解决竞争和冒险问题对于确保电路稳定运行非常重要。 竞争&#x…

facebook账号类型有哪些?

Facebook的主要账号类型 在Facebook上&#xff0c;用户可以基于不同的目的和需求创建不同类型的账号&#xff0c;主要包括以下几类&#xff1a; 1. 个人账号 这是最常见的Facebook账号类型&#xff0c;每个用户都可以创建一个个人账号&#xff0c;分享生活动态、与朋友互动、…

Unity 实现音频进度条(可控制)

目录 前言 一、拼UI 二、上代码 前言 效果如图&#xff1a;&#xff08;因为是GIF格式&#xff0c;录不上音频&#xff09; 一、拼UI 1.新建空物体添加AudioSource&#xff0c;给AudioSource添加音频文件&#xff0c;取消勾选PlayOnAwake&#xff0c;勾选上Loop 2.创建Slid…

FreeRTOS代码规范(3)

数据类型 portmacro.h : 在里面定义了Free RTOS 用到的相关数据类型 在 CM-3 内核中 short类型是16位&#xff0c;long 类型是32位 在 portmacro.h 中有两个最基本的数据类型 &#xff1a; Base type_t Tick type_t 这两个数据类型的存在是基于执行效率考虑的&#xff0c;…

Sigrity Power SI Resonance analysis模式如何进行谐振分析操作指导

Sigrity Power SI Resonance analysis模式如何进行谐振分析操作指导 Sigrity Power SI可以方便快捷的进行谐振分析,谐振分析的目的是为了分析电源地平面组成的腔体的谐振频率以及谐振幅度,让频率在谐振频率附近的信号避开谐振腔,以及添加相应的电容来降低谐振峰值. 仍然以这…

汽车IVI中控OS Linux driver开发实操(二十六):i.MX图形库

概述: 下表列出了整个GPU系列,在i.MX 6板上,只有6Quad和6QuadPlus支持OpenCL。表中还显示了OpenCL的关键性能指标GFLOPS的理论数量。一些基准测试,如Clpeak,可用于验证它。 i.MX G2D API G2D应用程序编程接口(API)设计为易于理解和使用2DBit blit(BLT)功能。它允许用…

[vulnhub]Kioptrix: Level 1.2 (#3)

https://www.vulnhub.com/entry/kioptrix-level-12-3,24/ 主机发现端口扫描 使用nmap扫描网段类存活主机 因为靶机是我最后添加的&#xff0c;所以靶机IP是169 nmap -sP 192.168.75.0/24 Starting Nmap 7.94SVN ( https://nmap.org ) at 2024-10-29 13:16 CST …

基于uniapp微信小程序的校园二手书交易系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码、微信小程序源码 精品专栏&#xff1a;…

【undefined reference to xxx】zookeeper库编译和安装 / sylar项目ubuntu20系统编译

最近学习sylar项目&#xff0c;编译项目时遇到链接库不匹配的问题&#xff0c;记录下自己解决问题过程&#xff0c;虽然过程很艰难&#xff0c;但还是解决了&#xff0c;以下内容供大家参考&#xff01; undefined reference to 问题分析 项目编译报错 /usr/bin/ld: ../lib/lib…

HTML练习题:彼岸的花(web)

展示效果: 代码: <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0"><title>彼岸の花</title><style…

构建灵活、高效的HTTP/1.1应用:探索h11库

文章目录 构建灵活、高效的HTTP/1.1应用&#xff1a;探索h11库背景这个库是什么&#xff1f;如何安装这个库&#xff1f;库函数使用方法使用场景常见的Bug及解决方案总结 构建灵活、高效的HTTP/1.1应用&#xff1a;探索h11库 背景 在现代网络应用中&#xff0c;HTTP协议是基础…

String的长度有限,而我对你的思念却无限延伸

公主请阅 1. 为什么学习string类&#xff1f;2. string类的常用接口2.1 string类对象的常见构造2.1.1 string 2.2 operator[]2.3 迭代器2.4 auto自动推导数据类型2.5 范围for2.6 迭代器第二层2.7 size和length获取字符串的长度2.8 max_size 获取这个字符串能设置的最大长度2.9 …