【问题标题】:Reading a Global Variable from a Thread and Writing to that Variable from another Thread从线程读取全局变量并从另一个线程写入该变量
【发布时间】:2013-08-16 05:05:07
【问题描述】:

我的程序有 2 个线程和一个 int 全局变量。一个线程正在读取该变量,而另一个线程正在写入该变量。在这种情况下我应该使用互斥锁吗?

这些函数在我的程序中同时从 2 个线程重复执行。

void thread1()
{
    if ( condition1 )
        iVariable = 1;
    else if ( condition2 )
        iVariable = 2;
}

void thread2()
{
    if ( iVariable == 1)
        //do something
    else if ( iVarable == 2 )
        //do another thing

}

【问题讨论】:

    标签: multithreading thread-safety mutex


    【解决方案1】:

    如果你不使用任何同步,那么当第二个线程看到更新的值时,它是完全不可预测的。这介于几纳秒和从不之间。当然,never 结果特别麻烦,当您不声明变量 volatile 并且运行程序的 Release 构建时,它可能发生在 x86 处理器上。在内存模型较弱的处理器(如 ARM 内核)上可能需要很长时间。您唯一不必担心的是看到部分更新的值,int 更新是原子的。

    关于发布的代码可以说的就是这些了。细粒度锁定很少能很好地发挥作用。

    【讨论】:

    • 说,thread1() 将把 1 分配给 iVariable(比如,iVariable 的旧值是 0)同时 thread2() 函数计算 if 条件中的 (iVariable == 1) 表达式。我知道 (iVariable == 1) 表达式返回的布尔值是不可预测的。但是我想知道在执行thread1()函数后,iVariable1的值是1还是其他垃圾值。
    • 这是我在回答中提到的“唯一不用担心的事情”。
    • 那就没什么好担心的了。并且没有必要使用互斥锁,因为不会将垃圾值分配给 iVariable。
    • 您似乎没有非常认真地对待我回答中的 never 子句。这确实不可避免地必须通过艰苦的方式来学习。
    • 我没听懂。您所说的“从不”是指它不会永远不会更新,尽管它应该更新。我说的对吗?
    【解决方案2】:

    是的,你应该(在大多数情况下)。互斥锁将确保您保护的数据在多个竞争 CPU 中正确可见。除非您有性能问题,否则您应该使用互斥锁。如果性能是一个问题,请查看无锁数据结构。

    【讨论】:

    • 如果没有围绕 iVariable 的互斥锁,很可能并非多核/CPU 系统中的所有 CPU 都会在您认为应该看到更新时看到更新。其中一些内存可见性竞争条件可能高度依赖于机器。因此,请使用互斥锁、自旋锁或原子变量。