g****t 发帖数: 31659 | 1 我们组每年卖x亿的量的嵌入式CPU
出过不少事故
我多年前也贡献过几行ROM code
理论上,你那个问题是没有答案的
因为你没写清楚while loop里面干啥了
也没说明白别的线程在干啥
你要是while loop里证明黎曼猜想呢?自己按按钮呢?改flag呢?...
实践上,
要先查自己应用的uncertainty sources
才能真正决定怎么办好
一般人就用atomic完事 |
w***g 发帖数: 5958 | 2 严重同意。据我理解,bihai的loop里其实在做一些
CPU intensive的事情,所以真不在乎在atomic上浪费
几个CPU cycle。
【在 g****t 的大作中提到】 : 我们组每年卖x亿的量的嵌入式CPU : 出过不少事故 : 我多年前也贡献过几行ROM code : 理论上,你那个问题是没有答案的 : 因为你没写清楚while loop里面干啥了 : 也没说明白别的线程在干啥 : 你要是while loop里证明黎曼猜想呢?自己按按钮呢?改flag呢?... : 实践上, : 要先查自己应用的uncertainty sources : 才能真正决定怎么办好
|
c*********e 发帖数: 16335 | 3 bihai这么做,逻辑上有问题。
UI按钮到底想让這個while loop运行几次?一次还是250次?运行多少次是根据什么来
定的?
确实,要看while loop里面到底要运行什么东西。
发信人: bihai (学得不好), 信区: Programming
标 题: 用volatile退出线程对不对?(C++)
发信站: BBS 未名空间站 (Sun Jul 9 06:49:16 2017, 美东)
网上很多说volatile和线程就没有关系。
我现在计划在线程里面
volatile bool quit=false;
void worker(){
while(!quit){
...
}
}
然后在一个UI的按钮那里
quit=true;
这样对不对?
【在 g****t 的大作中提到】 : 我们组每年卖x亿的量的嵌入式CPU : 出过不少事故 : 我多年前也贡献过几行ROM code : 理论上,你那个问题是没有答案的 : 因为你没写清楚while loop里面干啥了 : 也没说明白别的线程在干啥 : 你要是while loop里证明黎曼猜想呢?自己按按钮呢?改flag呢?... : 实践上, : 要先查自己应用的uncertainty sources : 才能真正决定怎么办好
|
d***a 发帖数: 13752 | 4 bihai的代码,UI进程设置一个flag变量,计算进程读到flag的变化后就退出了,确实
是用volatile就够了。
这种情况,最常见的是用IPC机制,简单可靠,也不需要关心下面的nasty的细节。IPC
的性能开销大一些,但计算进程都要退出了,这里没有性能上的问题。
【在 g****t 的大作中提到】 : 我们组每年卖x亿的量的嵌入式CPU : 出过不少事故 : 我多年前也贡献过几行ROM code : 理论上,你那个问题是没有答案的 : 因为你没写清楚while loop里面干啥了 : 也没说明白别的线程在干啥 : 你要是while loop里证明黎曼猜想呢?自己按按钮呢?改flag呢?... : 实践上, : 要先查自己应用的uncertainty sources : 才能真正决定怎么办好
|
g****t 发帖数: 31659 | 5 我喜欢用具体的例子代替不可判定情况的出现。
咱们假设bihai那个loop里面有一段是穷举黎曼猜想,
根据分支来调用OS别的硬件部分.
那这个问题是没办法回答什么是最好的办法了。
所以可能还是要明确那几路不确定性才行。
: bihai的代码,UI进程设置一个flag变量,计算进程读到flag的变化后就退出了
,确实
: 是用volatile就够了。
: 这种情况,最常见的是用IPC机制,简单可靠,也不需要关心下面的nasty的细节
。IPC
: 的性能开销大一些,但计算进程都要退出了,这里没有性能上的问题。
【在 d***a 的大作中提到】 : bihai的代码,UI进程设置一个flag变量,计算进程读到flag的变化后就退出了,确实 : 是用volatile就够了。 : 这种情况,最常见的是用IPC机制,简单可靠,也不需要关心下面的nasty的细节。IPC : 的性能开销大一些,但计算进程都要退出了,这里没有性能上的问题。
|
d***a 发帖数: 13752 | 6 把bihai的代码重写一下会看得清楚些。
void worker(){
while(true){
// check quit flag
if (quit)
return;
// start/continue the computation
...
}
}
从结构上说,其实并没有什么不确定的地方。UI thread只改变quit变量,并不改变其
它的共享变量。
【在 g****t 的大作中提到】 : 我喜欢用具体的例子代替不可判定情况的出现。 : 咱们假设bihai那个loop里面有一段是穷举黎曼猜想, : 根据分支来调用OS别的硬件部分. : 那这个问题是没办法回答什么是最好的办法了。 : 所以可能还是要明确那几路不确定性才行。 : : : bihai的代码,UI进程设置一个flag变量,计算进程读到flag的变化后就退出了 : ,确实 : : 是用volatile就够了。 : : 这种情况,最常见的是用IPC机制,简单可靠,也不需要关心下面的nasty的细节
|
g****t 发帖数: 31659 | 7 可能会有看不见的OS控制的中断进来吧?
例如ADC读数据什么的。
他那几个省略号也可能再查一次quit什么的
: 把bihai的代码重写一下会看得清楚些。
: void worker(){
: while(true){
: // check quit flag
: if (quit)
: return;
: // start/continue the computation
: ...
: }
: }
【在 d***a 的大作中提到】 : 把bihai的代码重写一下会看得清楚些。 : void worker(){ : while(true){ : // check quit flag : if (quit) : return; : // start/continue the computation : ... : } : }
|
d***a 发帖数: 13752 | 8 中断和读I/O的behavior是一样的吧,不管quit是volatile还是atomic类型。
再查一次quit是不要紧的。处理器的内存模型,必须保证单机访问内存的一致性,不会
说读quit拿到新值后,再读一次却拿到老值。
回到开始,我同意你说的原则,与性能无关的代码,应该越简单越好。对bihai的代码
来说,不管用volatile还是atomic类型的flag,都牵涉到硬件和系统底层的细节;用
IPC机制,更简单明了。在volatile和atomic之间,拿不准的时候应该用atomic,这也
是general guideline。但C++支持atomic,C并不支持,要用volatile再手动插入
memory barrier指令。
【在 g****t 的大作中提到】 : 可能会有看不见的OS控制的中断进来吧? : 例如ADC读数据什么的。 : 他那几个省略号也可能再查一次quit什么的 : : : 把bihai的代码重写一下会看得清楚些。 : : void worker(){ : : while(true){ : : // check quit flag : : if (quit) : : return;
|
g****t 发帖数: 31659 | 9 赞总结。
十个字
: 中断和读I/O的behavior是一样的吧,不管quit是volatile还是atomic类型。
: 再查一次quit是不要紧的。处理器的内存模型,必须保证单机访问内存的一致性
,不会
: 说读quit拿到新值后,再读一次却拿到老值。
: 回到开始,我同意你说的原则,与性能无关的代码,应该越简单越好。对bihai
的代码
: 来说,不管用volatile还是atomic类型的flag,都牵涉到硬件和系统底层的细节
;用
: IPC机制,更简单明了。在volatile和atomic之间,拿不准的时候应该用atomic
,这也
: 是general guideline。但C 支持atomic,C并不支持,要用volatile再手动插入
: memory barrier指令。
【在 d***a 的大作中提到】 : 中断和读I/O的behavior是一样的吧,不管quit是volatile还是atomic类型。 : 再查一次quit是不要紧的。处理器的内存模型,必须保证单机访问内存的一致性,不会 : 说读quit拿到新值后,再读一次却拿到老值。 : 回到开始,我同意你说的原则,与性能无关的代码,应该越简单越好。对bihai的代码 : 来说,不管用volatile还是atomic类型的flag,都牵涉到硬件和系统底层的细节;用 : IPC机制,更简单明了。在volatile和atomic之间,拿不准的时候应该用atomic,这也 : 是general guideline。但C++支持atomic,C并不支持,要用volatile再手动插入 : memory barrier指令。
|
b***i 发帖数: 3043 | 10 大家讨论很热烈。看来真的不在乎atomic上浪费几个时钟。
【在 w***g 的大作中提到】 : 严重同意。据我理解,bihai的loop里其实在做一些 : CPU intensive的事情,所以真不在乎在atomic上浪费 : 几个CPU cycle。
|
|
|
b***i 发帖数: 3043 | 11 UI按钮是让线程优美退出。本来这个while是一直运行的。
具体的例子,比如这个线程是一个lua的bytecode解释程序,那么while的条件就是看看
有没有下一个bytecode了,或者是不是要退出了。如果没有其他的代码了,或者要退出
了,这个解释程序的线程就退出。这个UI的按钮就是告诉线程在还有bytecode的代码的
时候就退出。
void luaInterpreter(...){
while(!quit && hasNextByteCode()){
processNextByteCode();
}
...
}
quit变量和Lua的解释程序的过程没有任何关系。所以我觉得reordering在这个应用里
面是没有关系的。另外bool在一个线程里写其他里读也不用保护。就剩下cache
coherence问题了。好像没有人提出过。
【在 c*********e 的大作中提到】 : bihai这么做,逻辑上有问题。 : UI按钮到底想让這個while loop运行几次?一次还是250次?运行多少次是根据什么来 : 定的? : 确实,要看while loop里面到底要运行什么东西。 : 发信人: bihai (学得不好), 信区: Programming : 标 题: 用volatile退出线程对不对?(C++) : 发信站: BBS 未名空间站 (Sun Jul 9 06:49:16 2017, 美东) : 网上很多说volatile和线程就没有关系。 : 我现在计划在线程里面 : volatile bool quit=false;
|
c*********e 发帖数: 16335 | 12 while(!quit && hasNextByteCode()){
這個!quit && hasNextByteCode()是atomic的吗?
【在 b***i 的大作中提到】 : UI按钮是让线程优美退出。本来这个while是一直运行的。 : 具体的例子,比如这个线程是一个lua的bytecode解释程序,那么while的条件就是看看 : 有没有下一个bytecode了,或者是不是要退出了。如果没有其他的代码了,或者要退出 : 了,这个解释程序的线程就退出。这个UI的按钮就是告诉线程在还有bytecode的代码的 : 时候就退出。 : void luaInterpreter(...){ : while(!quit && hasNextByteCode()){ : processNextByteCode(); : } : ...
|
b***i 发帖数: 3043 | 13 这里,既然说是lua的解释程序,它就不需要atomic,就是每个lua一个解释程序线程,
每个线程解释的是不同的bytecode,根本没有共享的信息,除了quit这个bool.我觉得一
个bool不需要atomic
【在 c*********e 的大作中提到】 : while(!quit && hasNextByteCode()){ : 這個!quit && hasNextByteCode()是atomic的吗?
|
g****t 发帖数: 31659 | 14 你没有给设计约束的情况下,在volatile 和 atomic中间肯定选atomic
: 大家讨论很热烈。看来真的不在乎atomic上浪费几个时钟。
【在 b***i 的大作中提到】 : 这里,既然说是lua的解释程序,它就不需要atomic,就是每个lua一个解释程序线程, : 每个线程解释的是不同的bytecode,根本没有共享的信息,除了quit这个bool.我觉得一 : 个bool不需要atomic
|
b***i 发帖数: 3043 | 15 我就是想问问到底错在哪
其实我觉得我这种情况用volatile没错,或者大家提到的memory barrier和lock都不是
问题。大多数情况在多线程下用atomic,但是这个特殊的情况有什么问题还没有人说清
楚。
【在 g****t 的大作中提到】 : 你没有给设计约束的情况下,在volatile 和 atomic中间肯定选atomic : : : 大家讨论很热烈。看来真的不在乎atomic上浪费几个时钟。 :
|
g****t 发帖数: 31659 | 16 我要是有人中断后,读你这个quit呢?
如果我的中断是快速硬件来的。例如电池没电了
读数据备份。
没有atomic, i = 1这句话
都未完成,硬件可能就读了。硬件读的信号
如果足够快,那在它的眼里,你这个变量的对应的
内存值就是不稳定的。
: 我就是想问问到底错在哪
: 其实我觉得我这种情况用volatile没错,或者大家提到的memory barrier
和lock
都不是
: 问题。大多数情况在多线程下用atomic,但是这个特殊的情况有什么问题
还没有
人说清
: 楚。
【在 b***i 的大作中提到】 : 我就是想问问到底错在哪 : 其实我觉得我这种情况用volatile没错,或者大家提到的memory barrier和lock都不是 : 问题。大多数情况在多线程下用atomic,但是这个特殊的情况有什么问题还没有人说清 : 楚。
|
w***g 发帖数: 5958 | 17 你理解没错,我给你endorse了: bihai这个volatile用得没错。
我们卖弄学问也希望你理解:)
:我就是想问问到底错在哪
: |
c*********e 发帖数: 16335 | 18 你要把完整的程序贴上来,才能对症下药。你这样遮遮掩掩的,没人能帮你。
【在 b***i 的大作中提到】 : 我就是想问问到底错在哪 : 其实我觉得我这种情况用volatile没错,或者大家提到的memory barrier和lock都不是 : 问题。大多数情况在多线程下用atomic,但是这个特殊的情况有什么问题还没有人说清 : 楚。
|
b***i 发帖数: 3043 | 19 这怎么还需要完整地程序,就是一个目的不行吗?
比如,计算矩阵乘法,需要80000x20000的自乘,可能需要很久吧。比如需要1小时。那
么,主程序有一个按钮,写着“开始”,还有一个本来是灰色的,写着“终止”
开始后,UI的函数就生成一个线程来执行乘法。可能是1个线程,也可能是多个。算了
20分钟,程序操作员发现有错误,需要终止计算重新开始,于是点击“终止”。当然,
线程们开始后这个“终止”按钮就不是灰色的了。
那么,此时,终止的UI函数就设置这个bool变量quit为真。然后个线程看到后就结束。
线程内部的乘法要经常查看quit变量。虽然不是while,但是就是那个意思。
for(rowA=0;rowA<20000;rowA++) {
for(rowB=0;rowB<20000;rowB++){
sum=0;
for(i=0;i<80000;i++)
sum+=A[rowA][i]*B[rowB][i];//A*B'
C[rowA][rowB]=sum;
}
if (quit)
break;
}
【在 c*********e 的大作中提到】 : 你要把完整的程序贴上来,才能对症下药。你这样遮遮掩掩的,没人能帮你。
|
w***g 发帖数: 5958 | 20 我再给你最后来一击:
#include
void loop_on_atomic (std::atomic *p) {
for (;;) {
if (*p) break;
}
}
g++ -std=c++11 -o xxx.s -S -O3 xxx.cpp
_Z14loop_on_atomicPSt6atomicIiE:
.LFB325:
.cfi_startproc
.p2align 4,,10
.p2align 3
.L2:
movl (%rdi), %eax
testl %eax, %eax
je .L2
rep ret
如果只是读取基本类型,atomic没有任何overhead啊。
咱move on吧。
【在 b***i 的大作中提到】 : 这怎么还需要完整地程序,就是一个目的不行吗? : 比如,计算矩阵乘法,需要80000x20000的自乘,可能需要很久吧。比如需要1小时。那 : 么,主程序有一个按钮,写着“开始”,还有一个本来是灰色的,写着“终止” : 开始后,UI的函数就生成一个线程来执行乘法。可能是1个线程,也可能是多个。算了 : 20分钟,程序操作员发现有错误,需要终止计算重新开始,于是点击“终止”。当然, : 线程们开始后这个“终止”按钮就不是灰色的了。 : 那么,此时,终止的UI函数就设置这个bool变量quit为真。然后个线程看到后就结束。 : 线程内部的乘法要经常查看quit变量。虽然不是while,但是就是那个意思。 : for(rowA=0;rowA<20000;rowA++) { : for(rowB=0;rowB<20000;rowB++){
|
|
|
b***i 发帖数: 3043 | 21 这不正说明对于bool变量, volatile足够了吗?当然,atomic的方法在x86上是没有
overhead的,不知道ARM等上有没有
【在 w***g 的大作中提到】 : 我再给你最后来一击: : #include : void loop_on_atomic (std::atomic *p) { : for (;;) { : if (*p) break; : } : } : g++ -std=c++11 -o xxx.s -S -O3 xxx.cpp : _Z14loop_on_atomicPSt6atomicIiE: : .LFB325:
|
b***i 发帖数: 3043 | 22 不懂你的意思。读quit的不是在线程里面吗?
【在 g****t 的大作中提到】 : 我要是有人中断后,读你这个quit呢? : 如果我的中断是快速硬件来的。例如电池没电了 : 读数据备份。 : 没有atomic, i = 1这句话 : 都未完成,硬件可能就读了。硬件读的信号 : 如果足够快,那在它的眼里,你这个变量的对应的 : 内存值就是不稳定的。 : : : 我就是想问问到底错在哪 : : 其实我觉得我这种情况用volatile没错,或者大家提到的memory barrier
|
g****t 发帖数: 31659 | 23 你这样想,假设i = 1赋值完成需要500秒。
在这个过程中有异常,操作系统要备份所有内存的快照,
下次重启的时候用。读出来有时候是1,有时候不是1,
对吧?
比较高级的操作系统这类问题是不会发生或者很少发生。
但是很多嵌入式就一个while死循环。atomic, volatile,
Yield, ....这些都是ROM代码汇编写的。
c编译器也是自造的。代码段,数据段,手工计算。
测试是往往要看一些信号的edge不互相mess up
: 不懂你的意思。读quit的不是在线程里面吗?
【在 b***i 的大作中提到】 : 不懂你的意思。读quit的不是在线程里面吗?
|
a9 发帖数: 21638 | 24 其实是不是原子操作或者volatile都没啥关系的吧。
有没有好的办法直接强制杀死线程的?
比如他这个,不检查这个quit标志,而是直接向这个线程发个指令这个线程就立刻中止
了?
【在 w***g 的大作中提到】 : 你理解没错,我给你endorse了: bihai这个volatile用得没错。 : 我们卖弄学问也希望你理解:) : : :我就是想问问到底错在哪 : :
|
d***a 发帖数: 13752 | 25 还在讨论啊。:)
用IPC机制中的signal就可以了,也是这种情况下的最常见做法。Unix terminal下用
Ctrl-C中断程序,就是由terminal进程向程序进程发一个kill的signal。bihai的程序
用的可能是多线程;进程和线程都可以发送和接受signal。
【在 a9 的大作中提到】 : 其实是不是原子操作或者volatile都没啥关系的吧。 : 有没有好的办法直接强制杀死线程的? : 比如他这个,不检查这个quit标志,而是直接向这个线程发个指令这个线程就立刻中止 : 了?
|
b***i 发帖数: 3043 | 26 多线程下想比较优美的退出。该log,该释放都得做。这样下次启动没有问题,不用重
启。
【在 d***a 的大作中提到】 : 还在讨论啊。:) : 用IPC机制中的signal就可以了,也是这种情况下的最常见做法。Unix terminal下用 : Ctrl-C中断程序,就是由terminal进程向程序进程发一个kill的signal。bihai的程序 : 用的可能是多线程;进程和线程都可以发送和接受signal。
|