zil*_*n01 4 multithreading synchronization locking thread-safety
在受限制的设备上,我经常发现自己在2个线程与2个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;
}
Run Code Online (Sandbox Code Playgroud)
当然在PC上我不会这样做,但在受限制的设备上,似乎读取一个bool值比获得锁定要快得多.当然,sleep(50)当需要更改缓冲区时,我需要权衡较慢的恢复(参见" ").
问题 - 它是完全线程安全的吗?或者在伪造这样的锁时我需要注意隐藏的陷阱吗?或者我应该不这样做?
使用bool值在线程之间进行通信可以按照您的意图工作,但确实存在两个隐藏的陷阱,如Vitaliy Liptchinsky在此博客文章中所述:
缓存一致性
CPU并不总是从RAM中获取内存值.芯片上的快速内存缓存是CPU设计人员用来解决Von Neumann瓶颈的技巧之一.在某些多CPU或多核架构(如Intel的Itanium)上,这些CPU缓存不会共享或自动保持同步.换句话说,如果它们在不同的CPU上运行,则您的线程可能会看到相同内存地址的不同值.
要避免这种情况,您需要将变量声明为volatile(C++,C#,java),或者执行显式易失性读/写,或者使用锁定机制.
编译器优化
如果涉及多个线程,编译器或JITter可以执行不安全的优化.有关示例,请参阅链接的博客文章.同样,您必须使用volatile关键字或其他机制来通知编译器.
除非您详细了解设备的内存架构以及编译器生成的代码,否则此代码并不安全.
仅仅因为看起来它会起作用,并不意味着它会."约束"设备,如无约束类型,正变得越来越强大.例如,我不打赌在手机中找到双核CPU.这意味着我不会打赌上面的代码会起作用.