在受限的设备上,我经常发现自己在两个线程之间使用两个bool“伪造”锁。每个线程只能由一个线程读取,并且只能由另一个线程写入。我的意思是:
bool quitted = false, paused = false;
bool should_quit = false, should_pause = false;
void downloader_thread() {
quitted = false;
while(!should_quit) {
fill_buffer(bfr);
if(should_pause) {
is_paused = true;
while(should_pause) sleep(50);
is_paused = false;
}
}
quitted = true;
}
void ui_thread() {
// new Thread(downloader_thread).start();
// ...
should_pause = true;
while(!is_paused) sleep(50);
// resize buffer or something else non-thread-safe
should_pause = false;
}当然,在PC上我不会这样做,但在受限的设备上,读取bool值似乎比获取锁要快得多。当然,当需要更改缓冲区时,我会牺牲较慢的恢复速度(参见"sleep(50)")。
问题是--它是完全线程安全的吗?或者有没有隐藏的陷阱,我需要注意的时候,像这样的假锁?或者我根本不应该这样做?
发布于 2009-04-23 18:20:20
除非您详细了解设备的内存体系结构以及编译器生成的代码,否则此代码是不安全的。
仅仅因为它看起来会工作,并不意味着它会工作。“受限”设备,如非受限类型,正变得越来越强大。例如,我不会打赌不能在手机中找到双核CPU。这意味着我不敢打赌上面的代码会工作。
发布于 2009-04-23 23:03:53
使用布尔值在线程之间进行通信可以按预期工作,但确实存在两个隐藏的陷阱,如this blog post by Vitaliy Liptchinsky中所述
缓存一致性
CPU并不总是从RAM中获取内存值。芯片上的快速内存缓存是CPU设计人员用来绕过Von Neumann bottleneck的诀窍之一。在某些多CPU或多核架构(如英特尔的Itanium)上,这些CPU缓存不是共享的,也不会自动保持同步。换句话说,如果你的线程运行在不同的CPU上,那么你的线程可能会看到相同内存地址的不同值。
为了避免这种情况,您需要将变量声明为volatile (C++、C#或do explicit volatile read/writes ),或者使用锁定机制。
编译器优化
如果涉及多个线程,编译器或JITter可能会执行不安全的优化。有关示例,请参阅链接的博客帖子。同样,您必须使用volatile关键字或其他机制来通知编译器。
发布于 2009-04-23 18:22:24
关于睡眠调用,你总是可以只做睡眠(0)或等效的调用,它会暂停你的线程,让下一个线程轮流。
关于其余部分,如果你知道你的设备的实现细节,这是线程安全的。
https://stackoverflow.com/questions/782912
复制相似问题