搜索
bottom↓
回复: 22

多线程操作共享变量的问题,求大佬解答!

[复制链接]
(10705316)

出0入0汤圆

发表于 2020-12-9 11:26:30 | 显示全部楼层 |阅读模式

volatile 解决多线程中数据不一致  , 每次读取数据都去主内存中读取 , 而不是去线程栈中读取 (线程栈里边可能存放的是旧值)。
但是我发现网上好多程序都没加volatile ,只用了信号量同步 , 是不是最好应该都加上关键字修饰呢 。。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
(10704741)

出0入20汤圆

发表于 2020-12-9 11:36:05 | 显示全部楼层
一个是链条锁,一个是汽车中控锁,你非要把上了锁的车再栓个链条锁也不是不行.

另外你这个基础知识不咋扎实哈,volatile本质上不是用来解决线程竞争的,也解决不了(在单片机这种场合读两次是常规操作).这就是一个用来强制同步的标识符,属于异步操作的范畴.
还有就是你用的什么天顶星科技堆栈不在内存里?
(10704443)

出0入0汤圆

发表于 2020-12-9 11:41:03 | 显示全部楼层
volatile 主要解决变量异步修改不一致(最好理解的就是STM32的所有寄存器变量全部加了volatile,应为这些变量是MCU随时会更新,不是你代码的一部分,所以需要每次程序读取都从实际地址去读,而不是内存的缓存),不是解决多线程同步的;
(10704263)

出0入100汤圆

发表于 2020-12-9 11:44:03 | 显示全部楼层
一个线程斋写,其它线程斋读,可以用volatile解决。不止一个线程会有写,则用信号量。
(10704215)

出0入20汤圆

发表于 2020-12-9 11:44:51 来自手机 | 显示全部楼层
Error.Dan 发表于 2020-12-9 11:36
一个是链条锁,一个是汽车中控锁,你非要把上了锁的车再栓个链条锁也不是不行.

另外你这个基础知识不咋扎实 ...

其实主要是编译器优化某些纯读和纯写变量时有时会sb,把纯写的丢了,纯读的省了。这严格来说可以算得上编译器的bug了。加volatile确实不是用来同步的,只是强制cpu做一次mov。当然用while1死等flag是可以同步的(仅限单读单写fifo类应用),而且效率并不低,比加锁快得多,实测zen2 3950x ccx内是33ns左右,跨ccx是72ns左右。
(10704108)

出0入0汤圆

 楼主| 发表于 2020-12-9 11:46:38 | 显示全部楼层
zzh90513 发表于 2020-12-9 11:41
volatile 主要解决变量异步修改不一致(最好理解的就是STM32的所有寄存器变量全部加了volatile,应为这些变 ...

两个线程共用一个标志位, 其中一个线程修改了值
那么 这种情况 为了防止线程之间数据不一致 ,是不是应该加上volatile呢
信号量 主要是针对不可重入函数把 。
(10704007)

出0入0汤圆

 楼主| 发表于 2020-12-9 11:48:19 | 显示全部楼层
wye11083 发表于 2020-12-9 11:44
其实主要是编译器优化某些纯读和纯写变量时有时会sb,把纯写的丢了,纯读的省了。这严格来说可以算得上编 ...

两个线程共用一个标志位, 其中一个线程修改了值
那么 这种情况 为了防止线程之间数据不一致 ,是不是应该加上volatile呢
信号量 主要是针对不可重入函数把 。 我理解的对吗?
(10703797)

出0入0汤圆

发表于 2020-12-9 11:51:49 | 显示全部楼层
sdasdas 发表于 2020-12-9 11:46
两个线程共用一个标志位, 其中一个线程修改了值
那么 这种情况 为了防止线程之间数据不一致 ,是不是应 ...

是的,这种可以加volatile解决;但这也是很多时候说的多线程尽量不要共享变量满天飞;一般这种情况,我都是将这些共享变量集中到一起,采用函数调用的方式写入和读取,然后统一加互斥锁
(10703792)

出0入100汤圆

发表于 2020-12-9 11:51:54 | 显示全部楼层
zzh90513 发表于 2020-12-9 11:41
volatile 主要解决变量异步修改不一致(最好理解的就是STM32的所有寄存器变量全部加了volatile,应为这些变 ...

您的理解有误,volatile是告诉编译器,这个机巴变量您每次都得从物理地址读,不能图省事,在寄存器/堆栈里读,说白了就是临时变量空间, 但不包括cache,cache是CPU掌控的范畴,对编译器是透明的。
(10703763)

出0入20汤圆

发表于 2020-12-9 11:52:23 来自手机 | 显示全部楼层
sdasdas 发表于 2020-12-9 11:48
两个线程共用一个标志位, 其中一个线程修改了值
那么 这种情况 为了防止线程之间数据不一致 ,是不是应 ...

想怎么用就怎么用。信号量是强同步(多c多p),volatile+while1是弱同步(单c单p)。
(10703712)

出0入0汤圆

 楼主| 发表于 2020-12-9 11:53:14 | 显示全部楼层
我理解的是 信号量 主要是防止共享资源出现“竞态”,防止被多个线程同时调用
而volatile  主要是多线程数据一致 , 从主内存中读取 , 而不是从寄存器副本取值
(10703589)

出0入0汤圆

发表于 2020-12-9 11:55:17 | 显示全部楼层
amigenius 发表于 2020-12-9 11:51
您的理解有误,volatile是告诉编译器,这个机巴变量您每次都得从物理地址读,不能图省事,在寄存器/堆栈 ...

恩,就是这个意思,是我说的“寄存器”表达不准确
(10703372)

出0入0汤圆

 楼主| 发表于 2020-12-9 11:58:54 | 显示全部楼层
wye11083 发表于 2020-12-9 11:44
其实主要是编译器优化某些纯读和纯写变量时有时会sb,把纯写的丢了,纯读的省了。这严格来说可以算得上编 ...

我理解的是 信号量 主要是防止共享资源出现“竞态”,防止被多个线程同时调用
而volatile  主要是多线程数据一致 , 从主内存中读取 , 而不是从寄存器副本取值  。
我理解错了吗? 大佬
我感觉 线程之间共享的标志位 做修改的时候   , volatile 关键字 保证县城数据一致性, 而信号量又能保证防止线程之间同时修改共享资源(不是原子操作)。
(10703161)

出0入20汤圆

发表于 2020-12-9 12:02:25 来自手机 | 显示全部楼层
sdasdas 发表于 2020-12-9 11:58
我理解的是 信号量 主要是防止共享资源出现“竞态”,防止被多个线程同时调用
而volatile  主要是多线程 ...

volatile是保证程序不被优化错!和同步没关系
(10703133)

出0入0汤圆

发表于 2020-12-9 12:02:53 | 显示全部楼层
sdasdas 发表于 2020-12-9 11:53
我理解的是 信号量 主要是防止共享资源出现“竞态”,防止被多个线程同时调用
而volatile  主要是多线程数 ...

对于共享变量,是这样的,为了避免编译器优化导致出错,加上这个是最保险的。
(10702489)

出0入0汤圆

 楼主| 发表于 2020-12-9 12:13:37 | 显示全部楼层
所以 ,我感觉是volatile 和 信号量都要加上。
我理解那里有偏差吗?
大佬多多指教~~

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
(10701798)

出0入0汤圆

发表于 2020-12-9 12:25:08 | 显示全部楼层
对于共享变量,读之前要invalid cache(从实际地址读取到缓存),写之后要write back cache(将缓存中的数据写回到实际内存)
(10701523)

出0入0汤圆

发表于 2020-12-9 12:29:43 | 显示全部楼层
sdasdas 发表于 2020-12-9 12:13
所以 ,我感觉是volatile 和 信号量都要加上。
我理解那里有偏差吗?
大佬多多指教~~ ...

只能说严谨的的解决方案,是这样的。
(10627614)

出0入0汤圆

发表于 2020-12-10 09:01:32 | 显示全部楼层
sdasdas 发表于 2020-12-9 12:13
所以 ,我感觉是volatile 和 信号量都要加上。
我理解那里有偏差吗?
大佬多多指教~~ ...

为什么a++不是原子操作呢? 有什么依据吗?
(10627125)

出0入0汤圆

发表于 2020-12-10 09:09:41 | 显示全部楼层
sdasdas 发表于 2020-12-9 12:13
所以 ,我感觉是volatile 和 信号量都要加上。
我理解那里有偏差吗?
大佬多多指教~~ ...

这个问题属到竞争问题,即使加上volatile 你也解决不了这个问题。
唯可行可以的是,将这个变量变成原子操作,即是在操作此寄存器时,禁止所有其它线程。
(10612924)

出240入221汤圆

发表于 2020-12-10 13:06:22 | 显示全部楼层
gonboy 发表于 2020-12-10 09:01
为什么a++不是原子操作呢? 有什么依据吗?

因为a++被编译为LDR,ADD,STR多条指令,指令之间可以被打断,所以不是原子操作。
像这种简短的变量共享,用关中断比较划算。
(5595246)

出0入0汤圆

发表于 2021-2-6 14:54:20 | 显示全部楼层
volatile是处于编译环节防止过度优化的,如果编译没问题,加不加无所谓,信号量是用于防止多线程冲突的,比如多核处理器多线程同时读写,必须要用信号量进行同步,不加一定会出错
(5576932)

出200入1737汤圆

发表于 2021-2-6 19:59:34 | 显示全部楼层
说 volatile 加不加都没事的,恐怕是程序调的少,我在盖革计里因为这个都快调试吐血了:

https://www.amobbs.com/thread-5741895-1-1.html
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子论坛 ( 公安交互式论坛备案:44190002001997 粤ICP备09047143号 )

GMT+8, 2021-4-12 09:08

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表