原始同步原语 - 安全吗?

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)当需要更改缓冲区时,我需要权衡较慢的恢复(参见" ").

问题 - 它是完全线程安全的吗?或者在伪造这样的锁时我需要注意隐藏的陷阱吗?或者我应该不这样做?

Wim*_*nen 6

使用bool值在线程之间进行通信可以按照您的意图工作,但确实存在两个隐藏的陷阱,如Vitaliy Liptchinsky此博客文章中所述:

缓存一致性

CPU并不总是从RAM中获取内存值.芯片上的快速内存缓存是CPU设计人员用来解决Von Neumann瓶颈的技巧之一.在某些多CPU或多核架构(如Intel的Itanium)上,这些CPU缓存不会共享或自动保持同步.换句话说,如果它们在不同的CPU上运行,则您的线程可能会看到相同内存地址的不同值.

要避免这种情况,您需要将变量声明为volatile(C++,C#,java),或者执行显式易失性读/写,或者使用锁定机制.

编译器优化

如果涉及多个线程,编译器或JITter可以执行不安全的优化.有关示例,请参阅链接的博客文章.同样,您必须使用volatile关键字或其他机制来通知编译器.


Joh*_*ers 5

除非您详细了解设备的内存架构以及编译器生成的代码,否则此代码并不安全.

仅仅因为看起来它会起作用,并不意味着它会."约束"设备,如无约束类型,正变得越来越强大.例如,我不打赌在手机中找到双核CPU.这意味着我不会打赌上面的代码会起作用.