返回信息流某人设计了一个定时炸弹。引爆装置在地址0x55aa55a0。向这个地址写入1就可以引爆炸弹。硬件时钟在地址0x70000000,读取的时候可以获取当前时间。于是可以这样写程序:
long* timer = (long*)0x70000000;
int* detonator = (int*)0x55aa55a0;
void detonate_at(long time) {
while(1) {
long cur_time = *timer;
if (cur_time >= time) {
*detonator = 1;
// unreachable. system destroyed.
}
}
}
但是优化器想帮你减少一些延迟,把程序改成这样:
long* timer = (long*)0x70000000;
int* detonator = (int*)0x55aa55a0;
void detonate_at(long time) {
while(1) {
long cur_time = *timer;
*detonator = 1; // speculative write
if (cur_time < time) {
*detonator = 0; // undo
}
}
}
然后,一些稀奇古怪的事情就发生了。一些恐怖分子报告说他的同伴一按下定时炸弹的按钮,炸弹就爆炸了。
即使参与C11 standard committee的Linux内核程序员也不是很确定C11的标准什么时候禁止“speculative write”。 http://lwn.net/Articles/586838/
这是一条镜像帖。来源:北邮人论坛 / cpp / #82051同步于 2014/9/1
该镜像源已超过 30 天没有更新,可能在源站已被删除。
CPP机器人发帖
为什么不要用C语言(包括C11)写定时炸弹的控制器
nuanyangyang
2014/9/1镜像同步8 回复
订阅后,新回复会通过你的通知中心匿名送达。
8 条回复
【 在 shan10211865 的大作中提到: 】
: 这么优化不就改变了逻辑了么。。。
如果大多数情况都是应该写入的,那么提前写入可以减小延迟。因为跳转需要时间,内存写入也需要时间。在单线程的情况下,大不了万一写错了再改回来。
比较典型的是下面这个例子:
int a = ...;
int b;
if (a == 1) {
b = 2; // 这个分支经常执行
} else {
b = 3; // 很少执行这个
}
如果优化器知道这个规律,再加上a和b都是局部变量,就可以这样优化:
int a = ...;
int b;
b = 2; // 这个经常执行
if (!(a == 1)) {
b = 3; // 很少执行这个
}
【 在 blackwc2006 的大作中提到: 】
: 把timer变量用volatile关键字修饰一下就好了吧...
: 发自「贵邮」
这样是可以的。
这不就是优化器先入为主了么,认为提出来的那句赋值是经常发生的,然而实际上并不是,不过确实优化了,本来是30s才完成的赋值,优化成了0s
另外:!(a==1) 比 a!=1 运行快?
【 在 nuanyangyang 的大作中提到: 】
:
: 如果大多数情况都是应该写入的,那么提前写入可以减小延迟。因为跳转需要时间,内存写入也需要时间。在单线程的情况下,大不了万一写错了再改回来。
: 比较典型的是下面这个例子:
: ...................
【 在 shan10211865 的大作中提到: 】
: 这不就是优化器先入为主了么,认为提出来的那句赋值是经常发生的,然而实际上并不是,不过确实优化了,本来是30s才完成的赋值,优化成了0s
: 另外:!(a==1) 比 a!=1 运行快?
这样的优化一般是有依据的,比如程序员会在if语句中插入提示,或者别的语言可以在运行时收集统计信息。
!(a==1)只是一个例子。具体写成机器码就是cmp然后je或者jne的区别了。