v*t
2 楼
我老初步估计五年
b*i
3 楼
网上很多说volatile和线程就没有关系。
我现在计划在线程里面
volatile bool quit=false;
void worker(){
while(!quit){
...
}
}
然后在一个UI的按钮那里
quit=true;
这样对不对?
我现在计划在线程里面
volatile bool quit=false;
void worker(){
while(!quit){
...
}
}
然后在一个UI的按钮那里
quit=true;
这样对不对?
s*o
4 楼
我一直写英文
s*m
5 楼
3-5 years
d*a
6 楼
这样做没问题,应该这样做。
f*k
11 楼
对这个圈子来说,这都没所谓吧。
r*k
15 楼
个人认为这个婚姻应该还比较稳定,因为女方是童星,相对别的女演员来说功利心稍微
少一些,男方年纪不小所以心态上应该比较成熟一点,加上他自己能力不强主要靠老爸
,将来想换老婆也很难找到比现在这个更好的了。
少一些,男方年纪不小所以心态上应该比较成熟一点,加上他自己能力不强主要靠老爸
,将来想换老婆也很难找到比现在这个更好的了。
h*c
27 楼
不是不对,是对同步得理解,同步没有semaphore或其他synchronization 机制会
starvation
说到这里,你对slicing得理解是怎样的,在什么样的情况下,你认为你应该研究一下
slicing?
starvation
说到这里,你对slicing得理解是怎样的,在什么样的情况下,你认为你应该研究一下
slicing?
b*i
29 楼
好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
新的方法是用C++的标准写法,有各种不同级别。
另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
所以还得代码自己解决这个问题。
【在 d***a 的大作中提到】
: 没有问题。worker()和UI代码在一个CPU上或不同CPU上运行都可以,如果后者是
: hardware shared memory的机器。
: 你的代码其实很简单,一个writer一个reader,只有一个共享变量。atomic是用来解决
: 更复杂的情况的。
:
: bool
能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
新的方法是用C++的标准写法,有各种不同级别。
另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
所以还得代码自己解决这个问题。
【在 d***a 的大作中提到】
: 没有问题。worker()和UI代码在一个CPU上或不同CPU上运行都可以,如果后者是
: hardware shared memory的机器。
: 你的代码其实很简单,一个writer一个reader,只有一个共享变量。atomic是用来解决
: 更复杂的情况的。
:
: bool
d*a
30 楼
有这种事?这几个CPU我全用过啊。:) 从机器层面来说,volatile的意思很简单,就是
要程序每次读写变量时都要访问内存,不要只对cpu register操作。
我觉得你的代码在这里可能有潜在问题:
while(!quit){
...
}
我记得在UI代码里,常见的写法是
while(!quit) {
sigwait(...); // or something similar, depending on the system
}
... // the work to do, e.g. quit the process
这样做的原因是,假设button代码不是在某种抢占方式下运行,那while(!quit)会把整
个程序阻塞住,button代码就没有机会被执行了,quit的值也就一直是false了。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
要程序每次读写变量时都要访问内存,不要只对cpu register操作。
我觉得你的代码在这里可能有潜在问题:
while(!quit){
...
}
我记得在UI代码里,常见的写法是
while(!quit) {
sigwait(...); // or something similar, depending on the system
}
... // the work to do, e.g. quit the process
这样做的原因是,假设button代码不是在某种抢占方式下运行,那while(!quit)会把整
个程序阻塞住,button代码就没有机会被执行了,quit的值也就一直是false了。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
M*t
31 楼
你这个关于volatile的说法是对的,volatile is just a hint to compiler。
另外,busy wait一般不是个好idea。可以考虑其他primitive。例如semaphore唤醒干
活,干完检查flag。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
另外,busy wait一般不是个好idea。可以考虑其他primitive。例如semaphore唤醒干
活,干完检查flag。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
M*t
32 楼
这些指令是编译器产生的,机器本身并不认识volatile。编译器可能想:这个值肯定是
这个呀,不用读memory呀,于是就优化掉了。volatile强迫编译器产生相应代码。
【在 d***a 的大作中提到】
: 有这种事?这几个CPU我全用过啊。:) 从机器层面来说,volatile的意思很简单,就是
: 要程序每次读写变量时都要访问内存,不要只对cpu register操作。
: 我觉得你的代码在这里可能有潜在问题:
: while(!quit){
: ...
: }
: 我记得在UI代码里,常见的写法是
: while(!quit) {
: sigwait(...); // or something similar, depending on the system
: }
这个呀,不用读memory呀,于是就优化掉了。volatile强迫编译器产生相应代码。
【在 d***a 的大作中提到】
: 有这种事?这几个CPU我全用过啊。:) 从机器层面来说,volatile的意思很简单,就是
: 要程序每次读写变量时都要访问内存,不要只对cpu register操作。
: 我觉得你的代码在这里可能有潜在问题:
: while(!quit){
: ...
: }
: 我记得在UI代码里,常见的写法是
: while(!quit) {
: sigwait(...); // or something similar, depending on the system
: }
F*n
39 楼
Don't use volatile. Your code is NOT guaranteed to be correct on all
platforms. Unlike in Java, volatile keyword in C++ does NOT enforce memory
barrier, and as a result, the code in your "while(!quit)" loop may be
reordered at the will of the compiler and/or the runtime system.
A rule of thumb in C/C++ is NEVER use volatile.
【在 b***i 的大作中提到】
: 网上很多说volatile和线程就没有关系。
: 我现在计划在线程里面
: volatile bool quit=false;
: void worker(){
: while(!quit){
: ...
: }
: }
: 然后在一个UI的按钮那里
: quit=true;
platforms. Unlike in Java, volatile keyword in C++ does NOT enforce memory
barrier, and as a result, the code in your "while(!quit)" loop may be
reordered at the will of the compiler and/or the runtime system.
A rule of thumb in C/C++ is NEVER use volatile.
【在 b***i 的大作中提到】
: 网上很多说volatile和线程就没有关系。
: 我现在计划在线程里面
: volatile bool quit=false;
: void worker(){
: while(!quit){
: ...
: }
: }
: 然后在一个UI的按钮那里
: quit=true;
c*e
40 楼
java里也不推荐用volatile.
【在 F****n 的大作中提到】
: Don't use volatile. Your code is NOT guaranteed to be correct on all
: platforms. Unlike in Java, volatile keyword in C++ does NOT enforce memory
: barrier, and as a result, the code in your "while(!quit)" loop may be
: reordered at the will of the compiler and/or the runtime system.
: A rule of thumb in C/C++ is NEVER use volatile.
【在 F****n 的大作中提到】
: Don't use volatile. Your code is NOT guaranteed to be correct on all
: platforms. Unlike in Java, volatile keyword in C++ does NOT enforce memory
: barrier, and as a result, the code in your "while(!quit)" loop may be
: reordered at the will of the compiler and/or the runtime system.
: A rule of thumb in C/C++ is NEVER use volatile.
w*z
41 楼
是你不推荐吧
:java里也不推荐用volatile.
:
:java里也不推荐用volatile.
:
S*A
42 楼
这个理解似乎不是很对。
volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
每个 memory load/store 都不能省,是有很明确的结果的。
load/store 的优化一般有:
同一个地方load 多次,中间没有写,后面的load和前面一样。
有多个store,前面的 store 可以去掉,最后一个 store 赢。
volatile 保证没有一个 load/store 被省略了。
其他派生出来的就是如何根据这个原理用而以。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
每个 memory load/store 都不能省,是有很明确的结果的。
load/store 的优化一般有:
同一个地方load 多次,中间没有写,后面的load和前面一样。
有多个store,前面的 store 可以去掉,最后一个 store 赢。
volatile 保证没有一个 load/store 被省略了。
其他派生出来的就是如何根据这个原理用而以。
【在 b***i 的大作中提到】
: 好像确实不对了,说的是某些CPU比如Alpha, ARM,和x86是不一样的,volatile自己不
: 能保证任何事情。完全取决于编译器是否还是按照原来的约定俗成的方案
: 新的方法是用C++的标准写法,有各种不同级别。
: 另外,退出线程除了busy wait,好像没有别的办法。即使OS能够在context switch的
: 时候查询是否要退出线程,但是没法正确的释放所有的资源,因为代码并没有执行完。
: 所以还得代码自己解决这个问题。
h*c
44 楼
当初记得是理解为volatile 是不会保留 thread local value,讲操作系统锁说过是两
boolean,说明设计者对可靠性的理解。
其实以前记得讨论过,用一个循环主要是处理missing signal,这个很讨厌,就是很贵
的solaris可能也不能保证notify.所以多线程,和多进程一样,也不一样,因为进程有
返回值,返回了就结束了,也可以wait, wait抓住信号,就可定结束了。但这两条对多
线程不适用。
这都是在实际中写出来的。但多线程的目的是什么呢,主要的目的比如,一个线程处理
一个socket,这样单个线程可以保证收发不影响别的socket。
这些东西也很依赖硬件实现。好在现在基本也都是X86-64.
总之,这个地方,你要问while loop 是对的,是为了处理missing signal, volatile
不volatile应该理解告诉每个thread 不要保留local copy,而是直接取共享值的地址,
也是告诉读程序的人,这个值是要共享的。
最后要理解的是,你永远无法判定一个线程或进程是否在运行,你只能知道它已经结束
了。所以volatile不volatile并不重要,但volatile更好些。
boolean,说明设计者对可靠性的理解。
其实以前记得讨论过,用一个循环主要是处理missing signal,这个很讨厌,就是很贵
的solaris可能也不能保证notify.所以多线程,和多进程一样,也不一样,因为进程有
返回值,返回了就结束了,也可以wait, wait抓住信号,就可定结束了。但这两条对多
线程不适用。
这都是在实际中写出来的。但多线程的目的是什么呢,主要的目的比如,一个线程处理
一个socket,这样单个线程可以保证收发不影响别的socket。
这些东西也很依赖硬件实现。好在现在基本也都是X86-64.
总之,这个地方,你要问while loop 是对的,是为了处理missing signal, volatile
不volatile应该理解告诉每个thread 不要保留local copy,而是直接取共享值的地址,
也是告诉读程序的人,这个值是要共享的。
最后要理解的是,你永远无法判定一个线程或进程是否在运行,你只能知道它已经结束
了。所以volatile不volatile并不重要,但volatile更好些。
F*n
45 楼
This is one of the most common misconceptions in C/C++ which have led to
numerous bugs in practice.
The fact is that in C/C++, volatile only tells the compiler "do not optimize
away" this variable. It says NOTHING about load/store operations.
Taking LZ's original post as an example, using volatile will only guarantee
his code will work in a single thread situation, but not in a multi-thread
situation.
You may wonder how could LZ's example be in a single-thread situation. You
are right - this is the reason the keyword volatile is almost useless. But
in rare cases, it is possible when the volatile variable is for hardware
access. That's the only valid use case for volatile in C/C++.
【在 S*A 的大作中提到】
: 这个理解似乎不是很对。
: volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以。
numerous bugs in practice.
The fact is that in C/C++, volatile only tells the compiler "do not optimize
away" this variable. It says NOTHING about load/store operations.
Taking LZ's original post as an example, using volatile will only guarantee
his code will work in a single thread situation, but not in a multi-thread
situation.
You may wonder how could LZ's example be in a single-thread situation. You
are right - this is the reason the keyword volatile is almost useless. But
in rare cases, it is possible when the volatile variable is for hardware
access. That's the only valid use case for volatile in C/C++.
【在 S*A 的大作中提到】
: 这个理解似乎不是很对。
: volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以。
F*n
46 楼
That's not correct. Java volatile is fine. It is equivalent to atomic
without compare.
I don't buy this immutable thing. Like design patterns, it is over-promoted
by biblical theorists with little practical experience, and it normally adds
a lot of unnecessary crap to a simple problem.
【在 c*********e 的大作中提到】
: java里用volatile,最好只用在bool上。现在有AtomicBoolean了,就不必要用
: volatile bool了。
: java里推荐用immutable.
without compare.
I don't buy this immutable thing. Like design patterns, it is over-promoted
by biblical theorists with little practical experience, and it normally adds
a lot of unnecessary crap to a simple problem.
【在 c*********e 的大作中提到】
: java里用volatile,最好只用在bool上。现在有AtomicBoolean了,就不必要用
: volatile bool了。
: java里推荐用immutable.
d*a
47 楼
草虫的理解是正确的。从体系结构和代码生成的角度来看,volatile是一个很简单的概
念。在语言层做大多的解读,反而把概念搞复杂了。
【在 S*A 的大作中提到】
: 这个理解似乎不是很对。
: volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以。
念。在语言层做大多的解读,反而把概念搞复杂了。
【在 S*A 的大作中提到】
: 这个理解似乎不是很对。
: volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以。
F*n
50 楼
https://en.wikipedia.org/wiki/Volatile_(computer_programming)
Quotes:
"Operations on volatile variables are not atomic, nor do they establish a
proper happens-before relationship for threading. This is specified in the
relevant standards (C, C++, POSIX, WIN32)..."
"According to the C++11 ISO Standard, the volatile keyword is only meant for
use for hardware access; do not use it for inter-thread communication."
Go read the wikipedia and ask questions here if you still don't understand.
I want to nail this down because I have seen too many people like you on
this and they caused trouble in practice.
【在 d***a 的大作中提到】
: You are wrong.
Quotes:
"Operations on volatile variables are not atomic, nor do they establish a
proper happens-before relationship for threading. This is specified in the
relevant standards (C, C++, POSIX, WIN32)..."
"According to the C++11 ISO Standard, the volatile keyword is only meant for
use for hardware access; do not use it for inter-thread communication."
Go read the wikipedia and ask questions here if you still don't understand.
I want to nail this down because I have seen too many people like you on
this and they caused trouble in practice.
【在 d***a 的大作中提到】
: You are wrong.
d*a
51 楼
Your understanding about those statements is wrong. What SSA said is
consistent with those statements.
What's why a CS major should have solid training in computer organization,
assembly programming, and complier construction. Otherwise, one may not even
know what he/she is talking about.
for
【在 F****n 的大作中提到】
: https://en.wikipedia.org/wiki/Volatile_(computer_programming)
: Quotes:
: "Operations on volatile variables are not atomic, nor do they establish a
: proper happens-before relationship for threading. This is specified in the
: relevant standards (C, C++, POSIX, WIN32)..."
: "According to the C++11 ISO Standard, the volatile keyword is only meant for
: use for hardware access; do not use it for inter-thread communication."
: Go read the wikipedia and ask questions here if you still don't understand.
: I want to nail this down because I have seen too many people like you on
: this and they caused trouble in practice.
consistent with those statements.
What's why a CS major should have solid training in computer organization,
assembly programming, and complier construction. Otherwise, one may not even
know what he/she is talking about.
for
【在 F****n 的大作中提到】
: https://en.wikipedia.org/wiki/Volatile_(computer_programming)
: Quotes:
: "Operations on volatile variables are not atomic, nor do they establish a
: proper happens-before relationship for threading. This is specified in the
: relevant standards (C, C++, POSIX, WIN32)..."
: "According to the C++11 ISO Standard, the volatile keyword is only meant for
: use for hardware access; do not use it for inter-thread communication."
: Go read the wikipedia and ask questions here if you still don't understand.
: I want to nail this down because I have seen too many people like you on
: this and they caused trouble in practice.
F*n
52 楼
你就不能谦虚一点?这是他的原话
"volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
每个 memory load/store 都不能省,是有很明确的结果的。
load/store 的优化一般有:
同一个地方load 多次,中间没有写,后面的load和前面一样。
有多个store,前面的 store 可以去掉,最后一个 store 赢。
volatile 保证没有一个 load/store 被省略了。
其他派生出来的就是如何根据这个原理用而以"
你跟我讲讲“不要优化这个变量 Load/Store 的操作。每个 memory load/store 都不
能省”
和C/C++的定义符合的?
恰恰相反,完全错误!
C/C++ volatile周围的load/stores可以随意被reorder优化!因为C/C++不像Java,它
的语言定义不包含内存模型,所谓的load/store这些东西,对C/C++语言本身来说是没
有任何意义的。而volatile是语言定义的一部分,自然也和load/store这些无关。
Memory model在C/C++里是通过atomic库来实现的。
even
【在 d***a 的大作中提到】
: Your understanding about those statements is wrong. What SSA said is
: consistent with those statements.
: What's why a CS major should have solid training in computer organization,
: assembly programming, and complier construction. Otherwise, one may not even
: know what he/she is talking about.
:
: for
"volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
每个 memory load/store 都不能省,是有很明确的结果的。
load/store 的优化一般有:
同一个地方load 多次,中间没有写,后面的load和前面一样。
有多个store,前面的 store 可以去掉,最后一个 store 赢。
volatile 保证没有一个 load/store 被省略了。
其他派生出来的就是如何根据这个原理用而以"
你跟我讲讲“不要优化这个变量 Load/Store 的操作。每个 memory load/store 都不
能省”
和C/C++的定义符合的?
恰恰相反,完全错误!
C/C++ volatile周围的load/stores可以随意被reorder优化!因为C/C++不像Java,它
的语言定义不包含内存模型,所谓的load/store这些东西,对C/C++语言本身来说是没
有任何意义的。而volatile是语言定义的一部分,自然也和load/store这些无关。
Memory model在C/C++里是通过atomic库来实现的。
even
【在 d***a 的大作中提到】
: Your understanding about those statements is wrong. What SSA said is
: consistent with those statements.
: What's why a CS major should have solid training in computer organization,
: assembly programming, and complier construction. Otherwise, one may not even
: know what he/she is talking about.
:
: for
d*a
53 楼
你没学过computer organization和assembly programming吧。SSA说的明显是对的,那
是CS本科必修课中的基本内容里的东西。
https://users.info.uvt.ro/~iordan/P_I/Ritchie-Kernighan-The_C_Programming_
Language_2_ed.pdf, page 232
The purpose of volatile is to force an implementation to suppress
optimization that could otherwise occur. For example, for a machine with
memory-mapped input/output, a pointer to a device register might be declared
as a pointer to volatile, in order to prevent the compiler from removing
apparently redundant references through the pointer.
"in order to prevent the compiler from removing apparently redundant
references", 在load/store的处理器架构上,指的就是不要去掉在正常优化下本来可
以去掉的load/store指令。
你要不要我给你写两段汇编代码,展示一下有volatile和没有volatile的区别?
PS SSA的原文有小的失误,"volatile就是告诉CPU不要优化这个变量Load/Store
的操作",应该是告诉compiler,不是告诉CPU。但对知道这个topic的人来说,不
会因此有误解。
【在 F****n 的大作中提到】
: 你就不能谦虚一点?这是他的原话
: "volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以"
: 你跟我讲讲“不要优化这个变量 Load/Store 的操作。每个 memory load/store 都不
: 能省”
是CS本科必修课中的基本内容里的东西。
https://users.info.uvt.ro/~iordan/P_I/Ritchie-Kernighan-The_C_Programming_
Language_2_ed.pdf, page 232
The purpose of volatile is to force an implementation to suppress
optimization that could otherwise occur. For example, for a machine with
memory-mapped input/output, a pointer to a device register might be declared
as a pointer to volatile, in order to prevent the compiler from removing
apparently redundant references through the pointer.
"in order to prevent the compiler from removing apparently redundant
references", 在load/store的处理器架构上,指的就是不要去掉在正常优化下本来可
以去掉的load/store指令。
你要不要我给你写两段汇编代码,展示一下有volatile和没有volatile的区别?
PS SSA的原文有小的失误,"volatile就是告诉CPU不要优化这个变量Load/Store
的操作",应该是告诉compiler,不是告诉CPU。但对知道这个topic的人来说,不
会因此有误解。
【在 F****n 的大作中提到】
: 你就不能谦虚一点?这是他的原话
: "volatile 就是告诉 CPU 不要优化这个变量 Load/Store 的操作。
: 每个 memory load/store 都不能省,是有很明确的结果的。
: load/store 的优化一般有:
: 同一个地方load 多次,中间没有写,后面的load和前面一样。
: 有多个store,前面的 store 可以去掉,最后一个 store 赢。
: volatile 保证没有一个 load/store 被省略了。
: 其他派生出来的就是如何根据这个原理用而以"
: 你跟我讲讲“不要优化这个变量 Load/Store 的操作。每个 memory load/store 都不
: 能省”
F*n
54 楼
你引用的原话里讲的包括
1. memory mapped IO,
2. a pointer to a device register
这两个跟他说的memory load/store 有什么关系? 你不会不清楚memory model是啥?
这两个就是我前面讲的跟硬件访问有关,现在的应用非常少,跟线程没有半点关系。
可笑的是不懂装懂,半瓶水响叮当,还computer organization和assembly
programming,真是无语了。
declared
【在 d***a 的大作中提到】
: 你没学过computer organization和assembly programming吧。SSA说的明显是对的,那
: 是CS本科必修课中的基本内容里的东西。
: https://users.info.uvt.ro/~iordan/P_I/Ritchie-Kernighan-The_C_Programming_
: Language_2_ed.pdf, page 232
: The purpose of volatile is to force an implementation to suppress
: optimization that could otherwise occur. For example, for a machine with
: memory-mapped input/output, a pointer to a device register might be declared
: as a pointer to volatile, in order to prevent the compiler from removing
: apparently redundant references through the pointer.
: "in order to prevent the compiler from removing apparently redundant
1. memory mapped IO,
2. a pointer to a device register
这两个跟他说的memory load/store 有什么关系? 你不会不清楚memory model是啥?
这两个就是我前面讲的跟硬件访问有关,现在的应用非常少,跟线程没有半点关系。
可笑的是不懂装懂,半瓶水响叮当,还computer organization和assembly
programming,真是无语了。
declared
【在 d***a 的大作中提到】
: 你没学过computer organization和assembly programming吧。SSA说的明显是对的,那
: 是CS本科必修课中的基本内容里的东西。
: https://users.info.uvt.ro/~iordan/P_I/Ritchie-Kernighan-The_C_Programming_
: Language_2_ed.pdf, page 232
: The purpose of volatile is to force an implementation to suppress
: optimization that could otherwise occur. For example, for a machine with
: memory-mapped input/output, a pointer to a device register might be declared
: as a pointer to volatile, in order to prevent the compiler from removing
: apparently redundant references through the pointer.
: "in order to prevent the compiler from removing apparently redundant
b*i
55 楼
我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
wiki,那只是一般来说的情况。
首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
底能有什么问题?
第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
before关系。没有任何其他变量的改写。
void uicallback(){
quit=true;//此前此后没有任何其他赋值
}
或者
void processTCPcallback(...){
if ...
if (condition)
quit=true;//此if前此后没有任何其他赋值
if ...
}
另外,前面有人说过什么busy waiting,也是没啥关系。这个线程里面不是一直在读这
个变量,读一次之后要做很多事情,比如10毫秒的工作。就是说这个while循环大概10
毫秒甚至1毫秒就读这个变量一次。置于这个变量改了之后,是不是线程立刻退出了,
那没啥关系。只要10-20毫秒内退出就行。
我希望大家讨论要根据这些具体的信息,而不是普通情况,而且要具体的不能用的原因
。都知道普通的多线程信息处理不能这样做。
基本情况就是,希望用Linux, 用C++,多线程,可能多CPU/多核心,CPU可能是x86,
x64, ARM等各类能够运行Linux的CPU。
for
【在 F****n 的大作中提到】
: https://en.wikipedia.org/wiki/Volatile_(computer_programming)
: Quotes:
: "Operations on volatile variables are not atomic, nor do they establish a
: proper happens-before relationship for threading. This is specified in the
: relevant standards (C, C++, POSIX, WIN32)..."
: "According to the C++11 ISO Standard, the volatile keyword is only meant for
: use for hardware access; do not use it for inter-thread communication."
: Go read the wikipedia and ask questions here if you still don't understand.
: I want to nail this down because I have seen too many people like you on
: this and they caused trouble in practice.
wiki,那只是一般来说的情况。
首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
底能有什么问题?
第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
before关系。没有任何其他变量的改写。
void uicallback(){
quit=true;//此前此后没有任何其他赋值
}
或者
void processTCPcallback(...){
if ...
if (condition)
quit=true;//此if前此后没有任何其他赋值
if ...
}
另外,前面有人说过什么busy waiting,也是没啥关系。这个线程里面不是一直在读这
个变量,读一次之后要做很多事情,比如10毫秒的工作。就是说这个while循环大概10
毫秒甚至1毫秒就读这个变量一次。置于这个变量改了之后,是不是线程立刻退出了,
那没啥关系。只要10-20毫秒内退出就行。
我希望大家讨论要根据这些具体的信息,而不是普通情况,而且要具体的不能用的原因
。都知道普通的多线程信息处理不能这样做。
基本情况就是,希望用Linux, 用C++,多线程,可能多CPU/多核心,CPU可能是x86,
x64, ARM等各类能够运行Linux的CPU。
for
【在 F****n 的大作中提到】
: https://en.wikipedia.org/wiki/Volatile_(computer_programming)
: Quotes:
: "Operations on volatile variables are not atomic, nor do they establish a
: proper happens-before relationship for threading. This is specified in the
: relevant standards (C, C++, POSIX, WIN32)..."
: "According to the C++11 ISO Standard, the volatile keyword is only meant for
: use for hardware access; do not use it for inter-thread communication."
: Go read the wikipedia and ask questions here if you still don't understand.
: I want to nail this down because I have seen too many people like you on
: this and they caused trouble in practice.
c*e
56 楼
compiler会打乱你的代码的顺序的。很多东西别想当然。你的代码要先经过compiler,
后来还要runtime.这些都不是你能控制的。
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
后来还要runtime.这些都不是你能控制的。
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
c*e
57 楼
volatile和atomic没有关系。
volatile是说到共享的memory里去找这个变量的值。
atomic是说是原子操作。
promoted
adds
【在 F****n 的大作中提到】
: That's not correct. Java volatile is fine. It is equivalent to atomic
: without compare.
: I don't buy this immutable thing. Like design patterns, it is over-promoted
: by biblical theorists with little practical experience, and it normally adds
: a lot of unnecessary crap to a simple problem.
volatile是说到共享的memory里去找这个变量的值。
atomic是说是原子操作。
promoted
adds
【在 F****n 的大作中提到】
: That's not correct. Java volatile is fine. It is equivalent to atomic
: without compare.
: I don't buy this immutable thing. Like design patterns, it is over-promoted
: by biblical theorists with little practical experience, and it normally adds
: a lot of unnecessary crap to a simple problem.
c*e
60 楼
网上抄的一个例子:
The belowcode snippet is not thread-safe
bool initialized;
if (!initialized) {
initialize();
initialized = true;
}
Hence in such situation, we fix it usingAtomic Boolean
AtomicBoolean initialized= new AtomicBoolean(false);
if (initialized.compareAndSet(false, true)) {
initialize();
}
【在 b***i 的大作中提到】
: 那bool(非atomic)到底为什么不是原子的?就一个bit难道不是最基本的构成?难道还
: 能三极管电压到达一半的程度?无法理解
The belowcode snippet is not thread-safe
bool initialized;
if (!initialized) {
initialize();
initialized = true;
}
Hence in such situation, we fix it usingAtomic Boolean
AtomicBoolean initialized= new AtomicBoolean(false);
if (initialized.compareAndSet(false, true)) {
initialize();
}
【在 b***i 的大作中提到】
: 那bool(非atomic)到底为什么不是原子的?就一个bit难道不是最基本的构成?难道还
: 能三极管电压到达一半的程度?无法理解
a9
61 楼
我觉得他那个完全没问题
你这个例子跟他的用法完全不是一回事儿,他只是在另一个线程里置个标志位而已。
大不子多跑一个循环10毫秒应该不影响他的结果
道还
【在 c*********e 的大作中提到】
: 网上抄的一个例子:
: The belowcode snippet is not thread-safe
: bool initialized;
: if (!initialized) {
: initialize();
: initialized = true;
: }
: Hence in such situation, we fix it usingAtomic Boolean
: AtomicBoolean initialized= new AtomicBoolean(false);
: if (initialized.compareAndSet(false, true)) {
你这个例子跟他的用法完全不是一回事儿,他只是在另一个线程里置个标志位而已。
大不子多跑一个循环10毫秒应该不影响他的结果
道还
【在 c*********e 的大作中提到】
: 网上抄的一个例子:
: The belowcode snippet is not thread-safe
: bool initialized;
: if (!initialized) {
: initialize();
: initialized = true;
: }
: Hence in such situation, we fix it usingAtomic Boolean
: AtomicBoolean initialized= new AtomicBoolean(false);
: if (initialized.compareAndSet(false, true)) {
p*o
62 楼
这个问题讨论这么久你还没明白什么重要。
首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
那后面就没啥好说的了。
其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
一页介绍,别提本科级别的汇编语言和体系结构课了。
最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
清楚了。
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
那后面就没啥好说的了。
其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
一页介绍,别提本科级别的汇编语言和体系结构课了。
最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
清楚了。
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
g*t
63 楼
他可能不理解这些东西的design motivation。
这类东西的根源,除了多线程,最容易理解的需求根源
是硬件驱动。这些往往是EE的内容。
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C 11的标准了,当然要遵循标准。你要是觉得按标准写
程序是
教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory
barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上
都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C 的std::atomic带memory barrier,这个是你需要的,至于CAS
这样的
atomic
: 操作那是另外的功能。另外java里的volatile和C 里的完全不一样,前
面也讨
论的很
: 清楚了。
: happens-
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
这类东西的根源,除了多线程,最容易理解的需求根源
是硬件驱动。这些往往是EE的内容。
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C 11的标准了,当然要遵循标准。你要是觉得按标准写
程序是
教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory
barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上
都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C 的std::atomic带memory barrier,这个是你需要的,至于CAS
这样的
atomic
: 操作那是另外的功能。另外java里的volatile和C 里的完全不一样,前
面也讨
论的很
: 清楚了。
: happens-
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
h*c
64 楼
it is f*cking s*ck, 解决问题远远让位于defending turf, even nobody where is
knows turfen is.
叔在这里透其实也都是早都讨论过的。当年good bug 在这里unix network
programming,叔还在提过的讨论,看看JVM unsafe那段C代码。
knows turfen is.
叔在这里透其实也都是早都讨论过的。当年good bug 在这里unix network
programming,叔还在提过的讨论,看看JVM unsafe那段C代码。
d*a
65 楼
老兄,你半懂不懂啊。你不是科班出身的,对吧。
volatile的基本含义就是如SSA所说,那是CS本科课程基础内容。你后来贴的wiki说法
,和SSA说的并不矛盾之处。这是为什么我说,you don't really know what you're
talking about。
楼主该不该用volatile, 和volatile是什么含义,从逻辑上说是两个不同的问题。
就楼主的代码而言,volatile就够了。他的代码的问题不在这里。
【在 F****n 的大作中提到】
: 你引用的原话里讲的包括
: 1. memory mapped IO,
: 2. a pointer to a device register
: 这两个跟他说的memory load/store 有什么关系? 你不会不清楚memory model是啥?
: 这两个就是我前面讲的跟硬件访问有关,现在的应用非常少,跟线程没有半点关系。
: 可笑的是不懂装懂,半瓶水响叮当,还computer organization和assembly
: programming,真是无语了。
:
: declared
volatile的基本含义就是如SSA所说,那是CS本科课程基础内容。你后来贴的wiki说法
,和SSA说的并不矛盾之处。这是为什么我说,you don't really know what you're
talking about。
楼主该不该用volatile, 和volatile是什么含义,从逻辑上说是两个不同的问题。
就楼主的代码而言,volatile就够了。他的代码的问题不在这里。
【在 F****n 的大作中提到】
: 你引用的原话里讲的包括
: 1. memory mapped IO,
: 2. a pointer to a device register
: 这两个跟他说的memory load/store 有什么关系? 你不会不清楚memory model是啥?
: 这两个就是我前面讲的跟硬件访问有关,现在的应用非常少,跟线程没有半点关系。
: 可笑的是不懂装懂,半瓶水响叮当,还computer organization和assembly
: programming,真是无语了。
:
: declared
d*a
66 楼
你的代码只有一次写共享变量,用不用atomic都可以。有多次写共享变量的情况下,就
要注意多次写的排序的问题,你的代码不是这样。
一般性的并行代码,会有多次写共享变量。那种情况下,用atomic比较安全。
你的代码,是运行不对吗? 我觉的首先要查的是控制结构与线程优先级。如果你用了多线
程,线程优先级设置不对,quit = true可能得不到执行的机会。如果你用了UI回调函数
(执行优先级高),那可能是别的什么地方不对, 但也要看具体用的是什么UI系统。
另外,你说的TCP的回调函数,具体是什么呢?
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
要注意多次写的排序的问题,你的代码不是这样。
一般性的并行代码,会有多次写共享变量。那种情况下,用atomic比较安全。
你的代码,是运行不对吗? 我觉的首先要查的是控制结构与线程优先级。如果你用了多线
程,线程优先级设置不对,quit = true可能得不到执行的机会。如果你用了UI回调函数
(执行优先级高),那可能是别的什么地方不对, 但也要看具体用的是什么UI系统。
另外,你说的TCP的回调函数,具体是什么呢?
happens-
【在 b***i 的大作中提到】
: 我觉得研究问题不能太教条,到现在还没人给出为什么不对的原因,只是引用标准和
: wiki,那只是一般来说的情况。
: 首先,我觉得atomic不是个事。在UI里面写这个变量,或者在TCP等待的线程里面写这
: 个变量,又不是读完再加一再写,到底能有什么atomic问题,请指出。就一个bool,到
: 底能有什么问题?
: 第二,读写顺序又有什么关系?就一个通知各线程退出的变量,也没有其他操作,可以
: 吗?UI/TCP的回叫函数里面改写这个变量为真然后函数退出。那么,根本没有happens-
: before关系。没有任何其他变量的改写。
: void uicallback(){
: quit=true;//此前此后没有任何其他赋值
b*i
67 楼
我并没有在实践中发现问题,只是问个理论的问题。
具体的TCP就是判断收到字符串"QUIT",那么就要求各线程退出。
多线
函数
【在 d***a 的大作中提到】
: 你的代码只有一次写共享变量,用不用atomic都可以。有多次写共享变量的情况下,就
: 要注意多次写的排序的问题,你的代码不是这样。
: 一般性的并行代码,会有多次写共享变量。那种情况下,用atomic比较安全。
: 你的代码,是运行不对吗? 我觉的首先要查的是控制结构与线程优先级。如果你用了多线
: 程,线程优先级设置不对,quit = true可能得不到执行的机会。如果你用了UI回调函数
: (执行优先级高),那可能是别的什么地方不对, 但也要看具体用的是什么UI系统。
: 另外,你说的TCP的回调函数,具体是什么呢?
:
: happens-
具体的TCP就是判断收到字符串"QUIT",那么就要求各线程退出。
多线
函数
【在 d***a 的大作中提到】
: 你的代码只有一次写共享变量,用不用atomic都可以。有多次写共享变量的情况下,就
: 要注意多次写的排序的问题,你的代码不是这样。
: 一般性的并行代码,会有多次写共享变量。那种情况下,用atomic比较安全。
: 你的代码,是运行不对吗? 我觉的首先要查的是控制结构与线程优先级。如果你用了多线
: 程,线程优先级设置不对,quit = true可能得不到执行的机会。如果你用了UI回调函数
: (执行优先级高),那可能是别的什么地方不对, 但也要看具体用的是什么UI系统。
: 另外,你说的TCP的回调函数,具体是什么呢?
:
: happens-
b*i
68 楼
我觉得不是memory barrier的问题。memory barrier前面有很多人提过,就是会防止打
乱次序。可是我代码里面设置quit=true;的语句前后没有其他代码。总不能把if的条件
和结果给打乱了吧?
UI回叫
void UIcallback(...){
quit=true;//这里没有任何其他语句
}
或者TCP处理的回叫
void TCPcallback(...){
...A
if (字符串=="QUIT")
quit=true;//这里没有任何其他语句
else
...B
...C
}
有个if在那里总不能把...A和quit=true;交换顺序吧?在这里即使有A/C这两个语句,
也是和quit=true互斥的,就是说我不可能在线程需要退出了还要继续进行其他的操作
。如果有人问那一定要进行其他的操作怎么办,比如释放资源。办法很简单,在线程的
while结束后操作。所以我说很多人引经据典都是对普通的情况的建议。对我这种具体
的情况,就一个bool,所以不需要critical section,就一个赋值,赋值前后没有其他
赋值,所以也不应该有memory barrier问题。
现在我倒是发现一个具体的问题,就是volatile不能保证信息是从内存读的,它只能保
证读入。这个读可能是cache里面的。那么多CPU就不能防止这个问题了。
stackoverflow上查Can I force cache coherency on a multicore x86 CPU?看到说多
CPU可能会有cache问题。
atomic
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
乱次序。可是我代码里面设置quit=true;的语句前后没有其他代码。总不能把if的条件
和结果给打乱了吧?
UI回叫
void UIcallback(...){
quit=true;//这里没有任何其他语句
}
或者TCP处理的回叫
void TCPcallback(...){
...A
if (字符串=="QUIT")
quit=true;//这里没有任何其他语句
else
...B
...C
}
有个if在那里总不能把...A和quit=true;交换顺序吧?在这里即使有A/C这两个语句,
也是和quit=true互斥的,就是说我不可能在线程需要退出了还要继续进行其他的操作
。如果有人问那一定要进行其他的操作怎么办,比如释放资源。办法很简单,在线程的
while结束后操作。所以我说很多人引经据典都是对普通的情况的建议。对我这种具体
的情况,就一个bool,所以不需要critical section,就一个赋值,赋值前后没有其他
赋值,所以也不应该有memory barrier问题。
现在我倒是发现一个具体的问题,就是volatile不能保证信息是从内存读的,它只能保
证读入。这个读可能是cache里面的。那么多CPU就不能防止这个问题了。
stackoverflow上查Can I force cache coherency on a multicore x86 CPU?看到说多
CPU可能会有cache问题。
atomic
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
d*a
70 楼
呵呵,barrier操作是parallel computing课中最基本的内容。但外系的学生来计算机
系修课,一般不会选parallel computing, 计算机系的学生也不是每个人都学。
楼主的程序并不需要memory barrier。Foxman的问题是并没有把情况搞清楚,死板地应
用概念,过于自以为是。
atomic
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
系修课,一般不会选parallel computing, 计算机系的学生也不是每个人都学。
楼主的程序并不需要memory barrier。Foxman的问题是并没有把情况搞清楚,死板地应
用概念,过于自以为是。
atomic
【在 p***o 的大作中提到】
: 这个问题讨论这么久你还没明白什么重要。
: 首先现在既然有C++11的标准了,当然要遵循标准。你要是觉得按标准写程序是教条,
: 那后面就没啥好说的了。
: 其次按标准来说,Foxman说的很对。你的疑惑在于不明白什么叫memory barrier。
: 这个东西别指望学校里能教,量化研究方法这种研究生体系结构教科书上都只花了
: 一页介绍,别提本科级别的汇编语言和体系结构课了。
: 最后,C++的std::atomic带memory barrier,这个是你需要的,至于CAS这样的atomic
: 操作那是另外的功能。另外java里的volatile和C++里的完全不一样,前面也讨论的很
: 清楚了。
:
w*g
72 楼
我就没学过,后来stackoverflow上学的。不过我承认我上parallel architecture
研究生课的时候一路都在打瞌睡。我曾经有跟楼主差不多的需要,纠结过一番
memory barrier,最后还是老老实实用了std::condition_variable。代码在这里
https://github.com/aaalgo/picpac/blob/master/picpac.h
省心,扩展容易,代码干净。
其实这种情况出现过多次,每次都觉得这么简单的情况不需要杀鸡用牛刀,
最后挖下去都发现水太深,然后用牛刀了事。
我印象中,操统课会讲IPC objects, mutex, sophomore这种。这些都是普世价值,
性能肯定有代价,但是一般没有坑。
【在 d***a 的大作中提到】
: 呵呵,barrier操作是parallel computing课中最基本的内容。但外系的学生来计算机
: 系修课,一般不会选parallel computing, 计算机系的学生也不是每个人都学。
: 楼主的程序并不需要memory barrier。Foxman的问题是并没有把情况搞清楚,死板地应
: 用概念,过于自以为是。
:
: atomic
研究生课的时候一路都在打瞌睡。我曾经有跟楼主差不多的需要,纠结过一番
memory barrier,最后还是老老实实用了std::condition_variable。代码在这里
https://github.com/aaalgo/picpac/blob/master/picpac.h
省心,扩展容易,代码干净。
其实这种情况出现过多次,每次都觉得这么简单的情况不需要杀鸡用牛刀,
最后挖下去都发现水太深,然后用牛刀了事。
我印象中,操统课会讲IPC objects, mutex, sophomore这种。这些都是普世价值,
性能肯定有代价,但是一般没有坑。
【在 d***a 的大作中提到】
: 呵呵,barrier操作是parallel computing课中最基本的内容。但外系的学生来计算机
: 系修课,一般不会选parallel computing, 计算机系的学生也不是每个人都学。
: 楼主的程序并不需要memory barrier。Foxman的问题是并没有把情况搞清楚,死板地应
: 用概念,过于自以为是。
:
: atomic
d*a
73 楼
握手。你PhD导师是这个领域的大牛啊,他的PhD论文我读过。
我以前有一段时间被迫搞过并行程序的性能优化,那个烦人,现有的轮子都不能用(性
能问题)。
bihai的代码,确实是用标准的IPC机制就可以的。我前面也给他说过,一般是用signal。
UI进程发个信号给计算进程,计算进程写个信号处理handler来做退出,就可以了。这
样做的好处就是绕过了底层那些nasty的细节。当然他的做法,小心一点也是可以的。
搞嵌入式编程的人喜欢用那种方式。
【在 w***g 的大作中提到】
: 我就没学过,后来stackoverflow上学的。不过我承认我上parallel architecture
: 研究生课的时候一路都在打瞌睡。我曾经有跟楼主差不多的需要,纠结过一番
: memory barrier,最后还是老老实实用了std::condition_variable。代码在这里
: https://github.com/aaalgo/picpac/blob/master/picpac.h
: 省心,扩展容易,代码干净。
: 其实这种情况出现过多次,每次都觉得这么简单的情况不需要杀鸡用牛刀,
: 最后挖下去都发现水太深,然后用牛刀了事。
: 我印象中,操统课会讲IPC objects, mutex, sophomore这种。这些都是普世价值,
: 性能肯定有代价,但是一般没有坑。
我以前有一段时间被迫搞过并行程序的性能优化,那个烦人,现有的轮子都不能用(性
能问题)。
bihai的代码,确实是用标准的IPC机制就可以的。我前面也给他说过,一般是用signal。
UI进程发个信号给计算进程,计算进程写个信号处理handler来做退出,就可以了。这
样做的好处就是绕过了底层那些nasty的细节。当然他的做法,小心一点也是可以的。
搞嵌入式编程的人喜欢用那种方式。
【在 w***g 的大作中提到】
: 我就没学过,后来stackoverflow上学的。不过我承认我上parallel architecture
: 研究生课的时候一路都在打瞌睡。我曾经有跟楼主差不多的需要,纠结过一番
: memory barrier,最后还是老老实实用了std::condition_variable。代码在这里
: https://github.com/aaalgo/picpac/blob/master/picpac.h
: 省心,扩展容易,代码干净。
: 其实这种情况出现过多次,每次都觉得这么简单的情况不需要杀鸡用牛刀,
: 最后挖下去都发现水太深,然后用牛刀了事。
: 我印象中,操统课会讲IPC objects, mutex, sophomore这种。这些都是普世价值,
: 性能肯定有代价,但是一般没有坑。
F*n
74 楼
那你加volatile的目的是什么?
你也知道cache访问会有问题,
这就是exactly memory barrier, reordering这些讲的东西
你的quit=true只要被调用周围就灰有代码。
【在 b***i 的大作中提到】
: 我觉得不是memory barrier的问题。memory barrier前面有很多人提过,就是会防止打
: 乱次序。可是我代码里面设置quit=true;的语句前后没有其他代码。总不能把if的条件
: 和结果给打乱了吧?
: UI回叫
: void UIcallback(...){
: quit=true;//这里没有任何其他语句
: }
: 或者TCP处理的回叫
: void TCPcallback(...){
: ...A
你也知道cache访问会有问题,
这就是exactly memory barrier, reordering这些讲的东西
你的quit=true只要被调用周围就灰有代码。
【在 b***i 的大作中提到】
: 我觉得不是memory barrier的问题。memory barrier前面有很多人提过,就是会防止打
: 乱次序。可是我代码里面设置quit=true;的语句前后没有其他代码。总不能把if的条件
: 和结果给打乱了吧?
: UI回叫
: void UIcallback(...){
: quit=true;//这里没有任何其他语句
: }
: 或者TCP处理的回叫
: void TCPcallback(...){
: ...A
F*n
76 楼
这个就是悖论,他那个condition只要被调用就会有代码
只有从来不会被调用才会完全没问题的
还有一种情况,并行计算中其实有些时候各个进程/线程之间的状态并不需要一致,
如果是这种情况下确实没问题,但是也不需要volatile,什么都不需要。
既然用了volatile就是对一致性有要求,不能说"我这个程序其实不需要一致性所以没
问题”。那你弄volatile是啥目的?
最后,C/C++和Java一个很大的不同就是C/C++很多情况下是全局优化,很多时候你根本
不能假设你的变量最后会怎么样,因为别人可能会调用你的code,然后别人调用代码周
围那些指令,和你的指令会被合在一起优化。
【在 a9 的大作中提到】
: 我觉得他那个完全没问题
: 你这个例子跟他的用法完全不是一回事儿,他只是在另一个线程里置个标志位而已。
: 大不子多跑一个循环10毫秒应该不影响他的结果
:
: 道还
只有从来不会被调用才会完全没问题的
还有一种情况,并行计算中其实有些时候各个进程/线程之间的状态并不需要一致,
如果是这种情况下确实没问题,但是也不需要volatile,什么都不需要。
既然用了volatile就是对一致性有要求,不能说"我这个程序其实不需要一致性所以没
问题”。那你弄volatile是啥目的?
最后,C/C++和Java一个很大的不同就是C/C++很多情况下是全局优化,很多时候你根本
不能假设你的变量最后会怎么样,因为别人可能会调用你的code,然后别人调用代码周
围那些指令,和你的指令会被合在一起优化。
【在 a9 的大作中提到】
: 我觉得他那个完全没问题
: 你这个例子跟他的用法完全不是一回事儿,他只是在另一个线程里置个标志位而已。
: 大不子多跑一个循环10毫秒应该不影响他的结果
:
: 道还
w*g
77 楼
楼上帮我看看下面的说法有没有问题。
memory barrier有两种:
1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
化级别不能解决hard barrier用错的问题。
外加一个独立的atomicity问题。
memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
hard barrier
的效果。std::atomic对于基本类型应该就是编译成__sync_fetch_and_xxx,复杂类型
应该是用锁实现,间接涉及__sync指令。所以不管怎样,也都有hard barrier的效果。
那么问题来了:gcc碰到hard barrier时会不会自动塞入soft barrier?
能不能举出一个例子,就是光用__sync_xxx还不够,非得用volatile才行的?
(另一个对称的问题,能不能举出一个例子,光用volatile就够了,不需要
__sync_xxx。这个问题的答案我相信就是楼主这个spin wait的问题。)
Update:
答案来了:gcc下__sync_synchronize()有volatile的作用。
int no_volatile_no_sync (int *i) {
*i = 1;
*i = 2;
}
int no_volatile_sync (int *i) {
*i = 1;
__sync_synchronize();
*i = 2;
}
如果用-O3编译,第一个输出为:
movl $2, (%rdi)
ret
第二个输出为
movl $1, (%rdi)
mfence
movl $2, (%rdi)
ret
除了__sync_xxx直接对应的mfence,前面那个赋值没有被优化掉。
我怀疑正因为gcc下hard barrier隐含soft barrier,所以导致网上盛行的一种
说法,就是volatile关键字没用。
Update 2:
硬加入mfence
int no_volatile_mfence (int *i) {
*i = 1;
asm("mfence");
*i = 2;
}
输出
mfence
movl $2, (%rdi)
ret
第一条赋值被干掉了。而改成asm("":::"memory")则会保留赋值。
所以__sync_synchronize等价于asm("mfence")和asm("":::"memory")联合用。
【在 F****n 的大作中提到】
: 这个就是悖论,他那个condition只要被调用就会有代码
: 只有从来不会被调用才会完全没问题的
: 还有一种情况,并行计算中其实有些时候各个进程/线程之间的状态并不需要一致,
: 如果是这种情况下确实没问题,但是也不需要volatile,什么都不需要。
: 既然用了volatile就是对一致性有要求,不能说"我这个程序其实不需要一致性所以没
: 问题”。那你弄volatile是啥目的?
: 最后,C/C++和Java一个很大的不同就是C/C++很多情况下是全局优化,很多时候你根本
: 不能假设你的变量最后会怎么样,因为别人可能会调用你的code,然后别人调用代码周
: 围那些指令,和你的指令会被合在一起优化。
memory barrier有两种:
1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
化级别不能解决hard barrier用错的问题。
外加一个独立的atomicity问题。
memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
hard barrier
的效果。std::atomic对于基本类型应该就是编译成__sync_fetch_and_xxx,复杂类型
应该是用锁实现,间接涉及__sync指令。所以不管怎样,也都有hard barrier的效果。
那么问题来了:gcc碰到hard barrier时会不会自动塞入soft barrier?
能不能举出一个例子,就是光用__sync_xxx还不够,非得用volatile才行的?
(另一个对称的问题,能不能举出一个例子,光用volatile就够了,不需要
__sync_xxx。这个问题的答案我相信就是楼主这个spin wait的问题。)
Update:
答案来了:gcc下__sync_synchronize()有volatile的作用。
int no_volatile_no_sync (int *i) {
*i = 1;
*i = 2;
}
int no_volatile_sync (int *i) {
*i = 1;
__sync_synchronize();
*i = 2;
}
如果用-O3编译,第一个输出为:
movl $2, (%rdi)
ret
第二个输出为
movl $1, (%rdi)
mfence
movl $2, (%rdi)
ret
除了__sync_xxx直接对应的mfence,前面那个赋值没有被优化掉。
我怀疑正因为gcc下hard barrier隐含soft barrier,所以导致网上盛行的一种
说法,就是volatile关键字没用。
Update 2:
硬加入mfence
int no_volatile_mfence (int *i) {
*i = 1;
asm("mfence");
*i = 2;
}
输出
mfence
movl $2, (%rdi)
ret
第一条赋值被干掉了。而改成asm("":::"memory")则会保留赋值。
所以__sync_synchronize等价于asm("mfence")和asm("":::"memory")联合用。
【在 F****n 的大作中提到】
: 这个就是悖论,他那个condition只要被调用就会有代码
: 只有从来不会被调用才会完全没问题的
: 还有一种情况,并行计算中其实有些时候各个进程/线程之间的状态并不需要一致,
: 如果是这种情况下确实没问题,但是也不需要volatile,什么都不需要。
: 既然用了volatile就是对一致性有要求,不能说"我这个程序其实不需要一致性所以没
: 问题”。那你弄volatile是啥目的?
: 最后,C/C++和Java一个很大的不同就是C/C++很多情况下是全局优化,很多时候你根本
: 不能假设你的变量最后会怎么样,因为别人可能会调用你的code,然后别人调用代码周
: 围那些指令,和你的指令会被合在一起优化。
d*a
78 楼
再加一个函数,看编译优化输出的代码,更清楚一些:
int volatile_no_sync (volatile int *i) {
*i = 1;
*i = 2;
}
汇编代码:
_no_volatile_no_sync
movl $2, (%rdi)
ret
_volatile_no_sync
movl $1, (%rdi)
movl $2, (%rdi)
ret
_no_volatile_sync
movl $1, (%rdi)
mfence
movl $2, (%rdi)
ret
我前面说过,如果从组织结构和代码生成的角度来看volatile和atomic,其实是很简单
的。volatile的作用就是要编译器不要去掉“多余”的内存访问;在load/store处理器
架构上是load/store指令,在x86架构上是有内存访问的mov指令。
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
int volatile_no_sync (volatile int *i) {
*i = 1;
*i = 2;
}
汇编代码:
_no_volatile_no_sync
movl $2, (%rdi)
ret
_volatile_no_sync
movl $1, (%rdi)
movl $2, (%rdi)
ret
_no_volatile_sync
movl $1, (%rdi)
mfence
movl $2, (%rdi)
ret
我前面说过,如果从组织结构和代码生成的角度来看volatile和atomic,其实是很简单
的。volatile的作用就是要编译器不要去掉“多余”的内存访问;在load/store处理器
架构上是load/store指令,在x86架构上是有内存访问的mov指令。
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
b*i
79 楼
我觉得cache的问题和memory barrier不是同一个问题。所以我一直认为reordering在
这里不会产生任何问题。
你想啊,我让线程退出,我还能有什么有用的信息告诉线程呢?会有什么错误呢?线程
都要退出了,做什么都不重要了。并不是我要传递几个参数,然后改写一个bool的变量
,然后希望线程读入那几个变量。这里除了quit没有任何其他变量的读写
【在 F****n 的大作中提到】
: 那你加volatile的目的是什么?
: 你也知道cache访问会有问题,
: 这就是exactly memory barrier, reordering这些讲的东西
: 你的quit=true只要被调用周围就灰有代码。
这里不会产生任何问题。
你想啊,我让线程退出,我还能有什么有用的信息告诉线程呢?会有什么错误呢?线程
都要退出了,做什么都不重要了。并不是我要传递几个参数,然后改写一个bool的变量
,然后希望线程读入那几个变量。这里除了quit没有任何其他变量的读写
【在 F****n 的大作中提到】
: 那你加volatile的目的是什么?
: 你也知道cache访问会有问题,
: 这就是exactly memory barrier, reordering这些讲的东西
: 你的quit=true只要被调用周围就灰有代码。
p*o
80 楼
你得分清楚标准和实现。按C++标准,volatile不需要带barrier/ordering,
std::atomic可以按你的需要选定几种ordering中的一个,包括你说的soft/hard。
事实上对程序员来说soft/hard应该保持一致,要不然程序就没法写了。
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
std::atomic可以按你的需要选定几种ordering中的一个,包括你说的soft/hard。
事实上对程序员来说soft/hard应该保持一致,要不然程序就没法写了。
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
F*n
83 楼
cache access 和 memory barrier 从reorder 优化的角度是一个道理
为什么recorder优化可行?是因为compiler发现你程序某些部分并不互相关联
所以把顺序换换也没关系。但在并行计算的情况下compiler很难通过语义分析(对C/C+
+来说)确定关联性,所以需要额外的memory barrier,它的一个作用就是把一定的顺
序强加在使用不同cache但访问同样内存地址区的并行进程。
为什么决大多数情况下用volatile退出线程不对? 简单的说,因为有数据一致性
要求时volatile不工作,没有数据一致性要求时,你根本不需要volatile。大多数情况
下你总不可能什么都不做就直接quit吧?总要对一些数据进行操作和判断然后决定是否
quit。举个不太恰当的例子:
Connection conn; // assumed to be a db connection;
bool volatile quit;
...
while (!quit) {
conn.doSomething(); // error if conn is closed
parkThread(100); //
}
if (conn.isOpen()) {
conn.close();
}
如果这是你的worker的逻辑,可能出现的问题是你点了quit button后,一个线程先
refresh发现quit变成了true 于是call conn.close(),但另一个线程的cache里 quit
还是false,还在call doSomething()。
可能很多人已经注意到了,其实如果conn.doSomething()自带logic检验是否close,上
面的程序就不会有任何问题。但如果这样的话,你会发现其实你也用不着volatile! 因
为你的数据conn已经不存在一致性问题了!这就是为什么C/C++里volatile大多数情况
下无用的原因:如果数据需要一致,用volatile是bug; 如果数据不需要一直,根本用
不着volatile。
前面已经讲了,C/C++ volatile唯一的作用就是让compiler不要把变量读写操作
optimize away。但这个作用实际上也是鸡肋。C/C++是全局编译优化,只要在编译单位
的任何一个地方出现了对“quit"的写操作,即使你自己的code里没有,别人import你
的code只要有,compiler就不会把他扔掉。一般来说,既然要通过quit来控制线程,就
必然在某些地方会对其进行写操作,所以volatile也就没什么用。只有少数几种情况是
例外,比如如果把quit map到一个shared memory区,然后完全由3rd party来update,
那么你的编译单位确实可以没有对quit的写操作,此时确实需要加volatile来防止编译
优化。这就是C/C++标准提到的volatile的几个use case,在实际应用中是比较罕见的。
【在 b***i 的大作中提到】
: 我觉得cache的问题和memory barrier不是同一个问题。所以我一直认为reordering在
: 这里不会产生任何问题。
: 你想啊,我让线程退出,我还能有什么有用的信息告诉线程呢?会有什么错误呢?线程
: 都要退出了,做什么都不重要了。并不是我要传递几个参数,然后改写一个bool的变量
: ,然后希望线程读入那几个变量。这里除了quit没有任何其他变量的读写
为什么recorder优化可行?是因为compiler发现你程序某些部分并不互相关联
所以把顺序换换也没关系。但在并行计算的情况下compiler很难通过语义分析(对C/C+
+来说)确定关联性,所以需要额外的memory barrier,它的一个作用就是把一定的顺
序强加在使用不同cache但访问同样内存地址区的并行进程。
为什么决大多数情况下用volatile退出线程不对? 简单的说,因为有数据一致性
要求时volatile不工作,没有数据一致性要求时,你根本不需要volatile。大多数情况
下你总不可能什么都不做就直接quit吧?总要对一些数据进行操作和判断然后决定是否
quit。举个不太恰当的例子:
Connection conn; // assumed to be a db connection;
bool volatile quit;
...
while (!quit) {
conn.doSomething(); // error if conn is closed
parkThread(100); //
}
if (conn.isOpen()) {
conn.close();
}
如果这是你的worker的逻辑,可能出现的问题是你点了quit button后,一个线程先
refresh发现quit变成了true 于是call conn.close(),但另一个线程的cache里 quit
还是false,还在call doSomething()。
可能很多人已经注意到了,其实如果conn.doSomething()自带logic检验是否close,上
面的程序就不会有任何问题。但如果这样的话,你会发现其实你也用不着volatile! 因
为你的数据conn已经不存在一致性问题了!这就是为什么C/C++里volatile大多数情况
下无用的原因:如果数据需要一致,用volatile是bug; 如果数据不需要一直,根本用
不着volatile。
前面已经讲了,C/C++ volatile唯一的作用就是让compiler不要把变量读写操作
optimize away。但这个作用实际上也是鸡肋。C/C++是全局编译优化,只要在编译单位
的任何一个地方出现了对“quit"的写操作,即使你自己的code里没有,别人import你
的code只要有,compiler就不会把他扔掉。一般来说,既然要通过quit来控制线程,就
必然在某些地方会对其进行写操作,所以volatile也就没什么用。只有少数几种情况是
例外,比如如果把quit map到一个shared memory区,然后完全由3rd party来update,
那么你的编译单位确实可以没有对quit的写操作,此时确实需要加volatile来防止编译
优化。这就是C/C++标准提到的volatile的几个use case,在实际应用中是比较罕见的。
【在 b***i 的大作中提到】
: 我觉得cache的问题和memory barrier不是同一个问题。所以我一直认为reordering在
: 这里不会产生任何问题。
: 你想啊,我让线程退出,我还能有什么有用的信息告诉线程呢?会有什么错误呢?线程
: 都要退出了,做什么都不重要了。并不是我要传递几个参数,然后改写一个bool的变量
: ,然后希望线程读入那几个变量。这里除了quit没有任何其他变量的读写
F*n
85 楼
你说的没错,__sync_fetch_and_xxx包括compiler barrier,文档里有提。
但C/C++里volatile没用的原因主要还是因为多数情况下,省略不省略和内存访问顺序
比,实在不重要。省略最多会漏掉一些初始值,顺序不对问题就大条了。所以gcc干脆
把compiler barrier 也加上省事。相反VC++则是把volatile变成跟Java一样fully
synchronized.
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
但C/C++里volatile没用的原因主要还是因为多数情况下,省略不省略和内存访问顺序
比,实在不重要。省略最多会漏掉一些初始值,顺序不对问题就大条了。所以gcc干脆
把compiler barrier 也加上省事。相反VC++则是把volatile变成跟Java一样fully
synchronized.
【在 w***g 的大作中提到】
: 楼上帮我看看下面的说法有没有问题。
: memory barrier有两种:
: 1. soft barrier: 阻止编译器乱优化。一般以volatile关键字的形式出现。编译后不
: 会产生对应的指令。有时候-O3出错,但是-O0对了,肯定是缺了soft barrier。
: 2. hard barrier: 阻止CPU乱执行。一般是以汇编指令/intrinsics的方式出现。改优
: 化级别不能解决hard barrier用错的问题。
: 外加一个独立的atomicity问题。
: memory barrier和atomicity是两个不同的问题。比如a = a+ 1这个操作,涉及读/算/
: 写,即使用了memory barrier,在多线程之下还是会出问题。然而反过来,要保证
: atomicity必须得用hard barrier。所以gcc的__sync_fetch_and_xxx系列指令全都有
a9
86 楼
你这是设计有问题。
如果你两个线程都要用数据库连接,那应该各自建一个单独的连接
或者在主线程里建连接,起两个线程,设置quit=true,等两个线程退出,然后断开连接
线程处理本来应该是相对独立的逻辑,你这种处理法用不用线程有什么意义吗
C+
quit
的。
reordering在
线程
变量
【在 F****n 的大作中提到】
: cache access 和 memory barrier 从reorder 优化的角度是一个道理
: 为什么recorder优化可行?是因为compiler发现你程序某些部分并不互相关联
: 所以把顺序换换也没关系。但在并行计算的情况下compiler很难通过语义分析(对C/C+
: +来说)确定关联性,所以需要额外的memory barrier,它的一个作用就是把一定的顺
: 序强加在使用不同cache但访问同样内存地址区的并行进程。
: 为什么决大多数情况下用volatile退出线程不对? 简单的说,因为有数据一致性
: 要求时volatile不工作,没有数据一致性要求时,你根本不需要volatile。大多数情况
: 下你总不可能什么都不做就直接quit吧?总要对一些数据进行操作和判断然后决定是否
: quit。举个不太恰当的例子:
: Connection conn; // assumed to be a db connection;
如果你两个线程都要用数据库连接,那应该各自建一个单独的连接
或者在主线程里建连接,起两个线程,设置quit=true,等两个线程退出,然后断开连接
线程处理本来应该是相对独立的逻辑,你这种处理法用不用线程有什么意义吗
C+
quit
的。
reordering在
线程
变量
【在 F****n 的大作中提到】
: cache access 和 memory barrier 从reorder 优化的角度是一个道理
: 为什么recorder优化可行?是因为compiler发现你程序某些部分并不互相关联
: 所以把顺序换换也没关系。但在并行计算的情况下compiler很难通过语义分析(对C/C+
: +来说)确定关联性,所以需要额外的memory barrier,它的一个作用就是把一定的顺
: 序强加在使用不同cache但访问同样内存地址区的并行进程。
: 为什么决大多数情况下用volatile退出线程不对? 简单的说,因为有数据一致性
: 要求时volatile不工作,没有数据一致性要求时,你根本不需要volatile。大多数情况
: 下你总不可能什么都不做就直接quit吧?总要对一些数据进行操作和判断然后决定是否
: quit。举个不太恰当的例子:
: Connection conn; // assumed to be a db connection;
b*i
88 楼
我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
就是说,既没有memory barrier问题,也没有原子操作问题。
没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操作需要
做可以在等待线程结束后的主线程那个join那里做。
原子的问题,是因为本来是bool,根本没有问题。
cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可以,因
为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
【在 F****n 的大作中提到】
: 你说的没错,__sync_fetch_and_xxx包括compiler barrier,文档里有提。
: 但C/C++里volatile没用的原因主要还是因为多数情况下,省略不省略和内存访问顺序
: 比,实在不重要。省略最多会漏掉一些初始值,顺序不对问题就大条了。所以gcc干脆
: 把compiler barrier 也加上省事。相反VC++则是把volatile变成跟Java一样fully
: synchronized.
就是说,既没有memory barrier问题,也没有原子操作问题。
没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操作需要
做可以在等待线程结束后的主线程那个join那里做。
原子的问题,是因为本来是bool,根本没有问题。
cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可以,因
为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
【在 F****n 的大作中提到】
: 你说的没错,__sync_fetch_and_xxx包括compiler barrier,文档里有提。
: 但C/C++里volatile没用的原因主要还是因为多数情况下,省略不省略和内存访问顺序
: 比,实在不重要。省略最多会漏掉一些初始值,顺序不对问题就大条了。所以gcc干脆
: 把compiler barrier 也加上省事。相反VC++则是把volatile变成跟Java一样fully
: synchronized.
g*t
89 楼
我说过了。不了解uncertainty sources的情况,用atomic.
可以假设i = 1的赋值需要500秒,想一想你需要不需要
0到1信号的上升沿完整。
这主要不是个逻辑问题。是个软件的设计问题。就是你要留多少Robustness margin,代
价多高。
你要自己玩。那怎么样都可以。如果要卖出去给人用,massive Users, 那是另一回事。
我看咱们大家可以搁置讨论,5年后再看。
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
: 就是说,既没有memory barrier问题,也没有原子操作问题。
: 没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操
作需要
: 做可以在等待线程结束后的主线程那个join那里做。
: 原子的问题,是因为本来是bool,根本没有问题。
: cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
: 其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可
以,因
: 为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
【在 b***i 的大作中提到】
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
: 就是说,既没有memory barrier问题,也没有原子操作问题。
: 没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操作需要
: 做可以在等待线程结束后的主线程那个join那里做。
: 原子的问题,是因为本来是bool,根本没有问题。
: cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
: 其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可以,因
: 为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
可以假设i = 1的赋值需要500秒,想一想你需要不需要
0到1信号的上升沿完整。
这主要不是个逻辑问题。是个软件的设计问题。就是你要留多少Robustness margin,代
价多高。
你要自己玩。那怎么样都可以。如果要卖出去给人用,massive Users, 那是另一回事。
我看咱们大家可以搁置讨论,5年后再看。
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
: 就是说,既没有memory barrier问题,也没有原子操作问题。
: 没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操
作需要
: 做可以在等待线程结束后的主线程那个join那里做。
: 原子的问题,是因为本来是bool,根本没有问题。
: cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
: 其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可
以,因
: 为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
【在 b***i 的大作中提到】
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
: 就是说,既没有memory barrier问题,也没有原子操作问题。
: 没有memory barrier是因为设置quit的时候之前之后没有任何操作。如果你有操作需要
: 做可以在等待线程结束后的主线程那个join那里做。
: 原子的问题,是因为本来是bool,根本没有问题。
: cache是因为本来硬件就是透明的,程序员不需要知道cache存在。
: 其他方面多线程一般不能使用volatile解决信息传递的问题。但是让线程终止可以,因
: 为线程都要中止了,还有啥可做的呢?放在Join那里就可以了。
b*i
90 楼
我们还真遇到这个问题,一个员工发现数字电路控制的开关除了问题,把电容给爆了。
怎么回事呢?
他的代码是这样的
if (toomuch==1)
op1...
if (toomuch==0)
op2
我一眼就发现了问题。这个toomuch是模拟信号,直接和数字信号1/0比较那么会遇到你
说的情况,在某个区间会既可能是1,又可能是0.而解决的方案是,把是1还是0的判断
做且只一次,再进行op1/op2,否则会出现两个都进行的情况。
if (toomuch)
toomuch_delayed = 1;
else
toomuch_delayed = 0;
...
if (toomuch_delayed)
op1...
所以你说的这个情况也是可以避免的,延时一个时钟即可。
事。
的。
【在 g****t 的大作中提到】
: 我说过了。不了解uncertainty sources的情况,用atomic.
: 可以假设i = 1的赋值需要500秒,想一想你需要不需要
: 0到1信号的上升沿完整。
: 这主要不是个逻辑问题。是个软件的设计问题。就是你要留多少Robustness margin,代
: 价多高。
: 你要自己玩。那怎么样都可以。如果要卖出去给人用,massive Users, 那是另一回事。
: 我看咱们大家可以搁置讨论,5年后再看。
:
:
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
:
: 就是说,既没有memory barrier问题,也没有原子操作问题。
怎么回事呢?
他的代码是这样的
if (toomuch==1)
op1...
if (toomuch==0)
op2
我一眼就发现了问题。这个toomuch是模拟信号,直接和数字信号1/0比较那么会遇到你
说的情况,在某个区间会既可能是1,又可能是0.而解决的方案是,把是1还是0的判断
做且只一次,再进行op1/op2,否则会出现两个都进行的情况。
if (toomuch)
toomuch_delayed = 1;
else
toomuch_delayed = 0;
...
if (toomuch_delayed)
op1...
所以你说的这个情况也是可以避免的,延时一个时钟即可。
事。
的。
【在 g****t 的大作中提到】
: 我说过了。不了解uncertainty sources的情况,用atomic.
: 可以假设i = 1的赋值需要500秒,想一想你需要不需要
: 0到1信号的上升沿完整。
: 这主要不是个逻辑问题。是个软件的设计问题。就是你要留多少Robustness margin,代
: 价多高。
: 你要自己玩。那怎么样都可以。如果要卖出去给人用,massive Users, 那是另一回事。
: 我看咱们大家可以搁置讨论,5年后再看。
:
:
: 我后来又查了,cache根本就是更无关的,所有volatile退出线程是没有问题的。
:
: 就是说,既没有memory barrier问题,也没有原子操作问题。
相关阅读
请各位帮我看看这个最简单的Stored Procedure请教计算关键词出现频率的算法Any difference between class and typename identifier?MPI问题求助。Help!help with PHP programming!!! (转载)VC 中如何修改默认的数组大小?请教server/client dllan interview problemHow to generate random number in driver (build in DDK)Segmentation faultarchitect?vb 6 to vb.net upgrade question打算安装mingw,我应该下哪些文件呢,问个SQL Server 2005问题 (转载)操作系统的新思路question on TCP slow starthelp: generate random IP address关于C的数组大小这里有没有人用OpenSSL的?Refactoring long class step by step (2)