Multithreading 线程之间的共享变量总是需要保护吗?

Multithreading 线程之间的共享变量总是需要保护吗?,multithreading,thread-safety,race-condition,Multithreading,Thread Safety,Race Condition,假设我有两个线程读取和修改bool/int“state”。处理器保证读写是原子的 Thread 1: if (state == ENABLED) { Process_Data() } Thread 2: state = DISABLED 在这种情况下,是的,线程1可以读取状态并进入“如果”状态来处理_数据,然后线程2可以更改状态。但在这一点上,继续处理数据并不是不正确的。是的,如果我们窥视引擎盖,我们会发现状态不一致,即被禁用,并且我们进入了Process_Data函数。但在下一

假设我有两个线程读取和修改bool/int“state”。处理器保证读写是原子的

Thread 1:

if (state == ENABLED)
{
    Process_Data()
}

Thread 2:

state = DISABLED
在这种情况下,是的,线程1可以读取状态并进入“如果”状态来处理_数据,然后线程2可以更改状态。但在这一点上,继续处理数据并不是不正确的。是的,如果我们窥视引擎盖,我们会发现状态不一致,即被禁用,并且我们进入了Process_Data函数。但在下一次执行Thread1时,它将被执行state=DISABLED,而不会处理_数据


我的问题是,我是否仍然需要在这两个线程中设置一个锁,以使Thread1的检查状态和进程原子化,以及Thread2的写入原子化(wrt到线程1)?

您已经解决了原子性问题。然而,在现代处理器中,不仅要担心原子性,还要担心内存可见性

例如,线程1在一个处理器上执行,并从其处理器的缓存中读取启用状态

同时,线程2正在另一个处理器上执行,并在其处理器的缓存中将禁用的写入状态写入到
state

如果没有进一步的代码-在某些语言中,例如,声明
状态
volatile-禁用的值可能无法长时间刷新到主内存。如果线程2最终将值更改回ENABLED,它可能永远不会刷新到主内存

同时,即使禁用的值被刷新到主内存,线程1也可能永远不会提取它,而是继续无限期地使用其缓存的ENABLED值


通常,如果您希望在线程之间共享值,最好明确地使用适用于您所使用的编程语言和环境的适当机制来共享值。

无法一般地回答您的问题。如果您正在使用的语言、编译器、线程库和/或平台的规范表明您需要保护,那么您确实需要保护。如果它说你没有,那么你就没有。我相信每个线程库或多线程实现都指定了合理使用和共享数据的规则。如果你的手机没有,那它就是一块无法可靠使用的垃圾,你应该买一个更好的


不要错误地认为,“这是安全的,因为我想不出任何可能出错的方式。”或者“我测试了它,但我无法让它失败,所以它是安全的。”这种想法会产生脆弱的代码,当您更改编译器选项、升级CPU或在其他平台上运行程序时,这些代码往往会失败。遵循所使用工具的规格。

一般来说,没有一种情况下你总是需要一些东西。(*永远,作为另一个绝对值,通常是错误的。)这将取决于您的用例。如前所述,当
状态实际上已禁用
时,您不介意运行
处理数据
,因此不需要锁。当然,这是假设
Process\u Data
不会与线程2上发生的任何事情发生冲突。“处理器的原子”只是意味着“不会发生中断的读/写”。这与内存可见性无关(在缓存一致性上读取)。
state=DISABLED
,如果没有任何编译器或硬件障碍,可能会导致thread1永远不会看到thread2执行
state=DISABLED
的效果,也就是说,仅仅因为它的“更安全”在我看来是错误的,就添加保护。我的问题是,如果没有发生数据损坏,那么实例的内部状态不一致是否可以接受。哪个平台或线程库说可以有内部状态不一致但没有数据损坏?我见过的大多数方法要么完全指定行为,要么将其记录为未定义/未指定。在大多数情况下,这种中间立场纯粹是虚构的。