另一个线程可以通过其地址访问本地函数\这个优化是不是有效\我错过了啥大事吗?
Posted
技术标签:
【中文标题】另一个线程可以通过其地址访问本地函数\\这个优化是不是有效\\我错过了啥大事吗?【英文标题】:Can another thread access function local by its address \ is this optimization valid \ am I missing something big?另一个线程可以通过其地址访问本地函数\这个优化是否有效\我错过了什么大事吗? 【发布时间】:2016-03-15 16:27:06 【问题描述】:想象一下这段代码:
线程1(功能):
#include <cstdio>
#include <thread>
struct t_arr
int _[2];
*volatile pvar = nullptr;
volatile bool var1;
void func(bool x, t_arr ar)
pvar = &ar;
(x ? ar._[0] : ar._[1]) = 90; //this whole statement optimized out
while(!var1);
typeof(func) *pFunc = func;
当我编译它时(确切的命令是g++ -O3 -std=gnu++1y snippet.cpp -pthread
),函数func
的结果主体缺少ar
成员之一被赋值为90 的分支。
这是允许的优化吗?
如果此时有另一个线程正在运行等待pvar
被赋值怎么办:
线程 2 (func2):
void func2()
while(!pvar); //wait until 'pvar' is assigned
printf("%d %d\n", pvar->_[0], pvar->_[1]); //print it members
var1 = true; //continue 'func'
创建上述情况的示例代码:
int main ()
using namespace std;
thread newthread(func2);
pFunc(true, 2, 9);
newthread.join();
return 0;
上面所有的sn-ps一个接一个地复制创建一个单一的源文件(snippet.cpp
)。
如果不是针对每一段单独的代码——谈论整个程序的意图是显而易见的。
sniper 的输出:
2 9
编辑:已修复 - 忘记加入。
【问题讨论】:
【参考方案1】:关于优化。通过变量ar
进行分配,该变量未标记为volatile
,指针pvar
是易失的。
因此,由于变量不再使用(就编译器而言),因此将这些赋值作为删除的候选者。
通过 volatile 指针进行赋值会阻止编译器对其进行优化。
(x ? pvar->_[0] : pvar->_[1]) = 90;
在此处查看代码示例;代码还没有优化出来,https://goo.gl/lKQcac。
注意;需要适当同步的数据竞争还有其他问题。
【讨论】:
【参考方案2】:来自函数func
的代码引入了不可避免的竞争条件 - 试图在读取变量的同时修改变量 - 由于竞争条件是未定义的行为,编译器不需要为未定义的行为生成代码。
如果要更改代码以便(可能)消除竞争条件,则会生成分配。下面是示例代码:
#include <thread>
#include <atomic>
#include <mutex>
struct t_arr
int _[2];
;
std::atomic<t_arr*> pvar(nullptr);
std::atomic<bool> var1;
void func(bool x, t_arr ar)
pvar = &ar;
(x ? ar._[0] : ar._[1]) = 90; //this whole statement optimized out
while(!var1);
上面的代码确实会生成分配。另请注意,我已将不恰当的 volatile
替换为正确的 std::atomic
。
【讨论】:
我将局部参数地址分配给一个全局变量,在func
执行期间允许读取。
@FISOCPP,由于代码无意中引入了数据竞争,编译器不需要生成代码来支持未定义的行为。如果您消除竞争条件,您将看到副本。让我用代码更新答案。
有人可以很好地解释投反对票的原因吗?
@SergeyA:我没有投反对票(后来来到这里......)。但是您的代码并没有消除竞争条件。
@SergeBallesta,它提供了一种理论上的可能性(如我的回答中所述!)通过编译器未知的代码消除竞争条件。这就是编译器不能丢弃赋值的原因。以上是关于另一个线程可以通过其地址访问本地函数\这个优化是不是有效\我错过了啥大事吗?的主要内容,如果未能解决你的问题,请参考以下文章
初学Linux,linux中使用ioremap函数可以映射一个数组吗?
C 程序是不是可以访问和更改分配给另一个程序的堆中的内存地址?