百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

编译器最受不了废话文学

liebian365 2025-01-04 21:17 55 浏览 0 评论


废话文学上一次这么流行的时候,还是在上一次流行废话文学的时候。


抖音上有个相声演员,每天的更新就是各种片汤话和废话,絮絮叨叨一大堆,一句有用的信息都没有。评论区都是调侃:“哎吓死我了,他差点就把正事说出来了”,“有领导开会那味儿了”。


还有一个最近爆火的叫陈依涵的小姐姐,每天更新一款无用的软件,诸如输入自己身高就能得出自己身高的计算器、百进制的分秒转换器等,也是废话文学的另一种表现形式。



与热衷于废话文学,被各种无厘头戳中笑点的我们相比,编译器就像个严肃高冷,追求效率,没有任何生活情趣的老头子一样,极其讨厌废话文学。


考虑这样一种情况:


x = 1;
x = 0;
x = 1;
x = 0;
x = 1;


编译器一看,好家伙,这不纯纯的废话嘛!

嵌入式物联网需要学的东西真的非常多,千万不要学错了路线和内容,导致工资要不上去!

无偿分享大家一个资料包,差不多150多G。里面学习内容、面经、项目都比较新也比较全!某鱼上买估计至少要好几十。

点击这里找小助理0元领取:https://s.pdb2.com/l/cnklSITCGo24eIn






于是编译器优化时很有可能会将上述五行代码优化为一行:


x = 1;


因为它觉得你这个人的水平太挫,说话也啰嗦,它要帮帮你。


可是,我这个x是表示板载LED的地址啊,我这么干,其实是想让这个LED闪烁...



这种编译器优化带来的问题,即使是原子量atomic也无能为力。此时我们从武器库里找到了另一把武器:volatile


volatile


volatile会告知编译器,对这种情况不要进行优化,保留这些看似冗余加载和废弃存储的无效操作,虽然是废话,但是我爱听。


这几乎是volatile最适用的场景了,其他场景我觉得volatile都不算是最优解。


我们来回顾一下一些教材上对C/C++里volatile关键字的解释:


volatile提醒编译器它后面所修饰的变量随时都有可能改变,因此编译后的程序每次需要存储或读取这个变量的时候,告诉编译器对该变量不做优化,都会直接从变量内存地址中读取数据,从而可以提供对特殊地址的稳定访问。


翻译翻译就是volatile会保证本线程对变量做的修改,都会立即被其他线程感知到。说官方点就是对其他线程可见,说人话就是其他线程拿到的值都是最新的,是修改生效的。


看了上篇文章的读者,一定会想到内存序。这不就是内存序的功能嘛?


而且内存序还要比它强大的多,因为volatile只能保证被volatile修饰的变量对其他线程可见,而原子量+内存序不仅可以保证对原子变量的修改对其他线程可见,还可以确保内存里其他变量的修改都对所有线程可见!


atomic


以上一篇文章《如何帮罗小猪的时间管理进一步提高性能?无锁并发!》提到过的这样一种情况为例:


?// 计算值
data = calculate();
//设置flag,通知其他任务值已可用
flag =
true;


编译器优化很有可能会把flag=true这句放到calculate计算值之前!因为它觉得两者似乎是不同的内存不同的寄存器。


编译器说我估计calculate函数还要花费一点时间才能执行完,索性就先把下面的flag=true给执行了。反正内存地址不是同一个,不冲突。


但这却有可能会让其他监听flag状态的线程提前执行,完全违背了我们的设计初衷。


这时如果我们将flag用原子量atomic来定义,用store(memory_order_release)来赋值,则可以保证上述代码的正常执行次序,防止被其他线程在flag未设置之前拿到计算值。



但这种情况,volatile是无能为力的。假如用volatile来修饰flag的话,它最多保证flag的变化能立刻被另一线程感知到,但却无法保证另一个线程拿到的data是被calculate过的。即C/C++里的volatile对于指令重排序无法进行限制


况且,volatile还有个致命的问题是,它并不能保证变量操作的原子性。也就是说,虽然你对其他线程可见,但你的值并不一定符合预期。


比如用volatile修饰一个变量value:


volatile int value = 0;
value++;
value--;
std::cout<<value;


如果有一个线程正在执行这段代码,另一个线程去读取value的值的话,那这个值会出现无数种可能,甚至可能是负数或者一个特别大的数。


因为某个线程刚刚在value这块内存上写了一半,就被另一个线程读取,那么它读到的这个值属于未定义行为,没有任何意义。


基于以上两点,即:

1.volatile不能保证原子操作。

2.volatile不能限制指令重排序。


所以并发多任务的情况下用volatile可能并不是一个好的选择。



总结一下,像状态寄存器、映射到内存地址上的 I/O 操作、涉及硬件操作的变量需要加volatile,因为对它们的每一次操作都有其意义,并不是废话文学。


而并发时,多线程多任务环境下各任务间共享的标志,其实更应该用原子量和内存序,或者直接加互斥锁,以确保共享区操作的原子性和顺序性。


所以其实volatile和atomic是应用于不同场景的,甚至可以叠加使用。比如:


volatile std::atomic<int> value;


这个式子表示对value的操作都是原子性的,并且它的废话文学也不可以被优化掉。


后 记


最近发的文章关于C/C++语言方面的比较多,事实上我是打算先从语言基础开始,后续关于编译器、单片机、RTOS、Linux应用、内核、驱动等嵌入式相关的技术知识和经验技巧,以及博主从事过的物联网、半导体行业的实战经验和职场分享,都会陆续在这个号上发布。

原文作者:李纳克斯Linux

原文标题:编译器最受不了废话文学
原文链接:https://mp.weixin.qq.com/s/e8zgh0oC2A-WE5crvCF5Bw

相关推荐

go语言也可以做gui,go-fltk让你做出c++级别的桌面应用

大家都知道go语言生态并没有什么好的gui开发框架,“能用”的一个手就能数的清,好用的就更是少之又少。今天为大家推荐一个go的gui库go-fltk。它是通过cgo调用了c++的fltk库,性能非常高...

旧电脑的首选系统:TinyCore!体积小+精简+速度极快,你敢安装吗

这几天老毛桃整理了几个微型Linux发行版,准备分享给大家。要知道可供我们日常使用的Linux发行版有很多,但其中的一些发行版经常会被大家忽视。其实这些微型Linux发行版是一种非常强大的创新:在一台...

codeblocks和VS2019下的fltk使用中文

在fltk中用中文有点问题。英文是这样。中文就成这个样子了。我查了查资料,说用UTF-8编码就行了。edit->Fileencoding->UTF-8然后保存文件。看下下边的编码指示确...

FLTK(Fast Light Toolkit)一个轻量级的跨平台Python GUI库

FLTK(FastLightToolkit)是一个轻量级的跨平台GUI库,特别适用于开发需要快速、高效且简单界面的应用程序。本文将介绍Python中的FLTK库,包括其特性、应用场景以及如何通过代...

中科院开源 RISC-V 处理器“香山”流片,已成功运行 Linux

IT之家1月29日消息,去年6月份,中科院大学教授、中科院计算所研究员包云岗,发布了开源高性能RISC-V处理器核心——香山。近日,包云岗在社交平台晒出图片,香山芯片已流片,回片后...

Linux 5.13内核有望合并对苹果M1处理器支持的初步代码

预计Linux5.13将初步支持苹果SiliconM1处理器,不过完整的支持工作可能还需要几年时间才能完全完成。虽然Linux已经可以在苹果SiliconM1上运行,但这需要通过一系列的补丁才能...

Ubuntu系统下COM口测试教程(ubuntu port)

1、在待测试的板上下载minicom,下载minicom有两种方法:方法一:在Ubuntu软件中心里面搜索下载方法二:按“Ctrl+Alt+T”打开终端,打开终端后输入“sudosu”回车;在下...

湖北嵌入式软件工程师培训怎么选,让自己脱颖而出

很多年轻人毕业即失业、面试总是不如意、薪酬不满意、在家躺平。“就业难”该如何应对,参加培训是否能改变自己的职业走向,在湖北,有哪些嵌入式软件工程师培训怎么选值得推荐?粤嵌科技在嵌入式培训领域有十几年经...

新阁上位机开发---10年工程师的Modbus总结

前言我算了一下,今年是我跟Modbus相识的第10年,从最开始的简单应用到协议了解,从协议开发到协议讲解,这个陪伴了10年的协议,它一直没变,变的只是我对它的理解和认识。我一直认为Modbus协议的存...

创建你的第一个可运行的嵌入式Linux系统-5

@ZHangZMo在MicrochipBuildroot中配置QT5选择Graphic配置文件增加QT5的配置修改根文件系统支持QT5修改output/target/etc/profile配置文件...

如何在Linux下给zigbee CC2530实现上位机

0、前言网友提问如下:粉丝提问项目框架汇总下这个网友的问题,其实就是实现一个网关程序,内容分为几块:下位机,通过串口与上位机相连;下位机要能够接收上位机下发的命令,并解析这些命令;下位机能够根据这些命...

Python实现串口助手 - 03串口功能实现

 串口调试助手是最核心的当然是串口数据收发与显示的功能,pzh-py-com借助的是pySerial库实现串口收发功能,今天痞子衡为大家介绍pySerial是如何在pzh-py-com发挥功能的。一、...

为什么选择UART(串口)作为调试接口,而不是I2C、SPI等其他接口

UART(通用异步收发传输器)通常被选作调试接口有以下几个原因:简单性:协议简单:UART的协议非常简单,只需设置波特率、数据位、停止位和校验位就可以进行通信。相比之下,I2C和SPI需要处理更多的通...

同一个类,不同代码,Qt 串口类QSerialPort 与各种外设通讯处理

串口通讯在各种外设通讯中是常见接口,因为各种嵌入式CPU中串口标配,工业控制中如果不够还通过各种串口芯片进行扩展。比如spi接口的W25Q128FV.对于软件而言,因为驱动接口固定,软件也相对好写,因...

嵌入式linux为什么可以通过PC上的串口去执行命令?

1、uboot(负责初始化基本硬bai件,如串口,网卡,usb口等,然du后引导系统zhi运行)2、linux系统(真正的操作系统)3、你的应用程序(基于操作系统的软件应用)当你开发板上电时,u...

取消回复欢迎 发表评论: