【问题标题】:Can static local variable be wrongly optimized?静态局部变量会被错误地优化吗?
【发布时间】:2017-12-16 14:55:10
【问题描述】:
std::uint64_t foo()
{
    static std::uint64_t var = 0u;

    std::lock_guard<std::mutex> lock(mutex);

    std::uint64_t b;

    do
    {
        b = bar();
    }
    while (b <= var);

    var = b;

    return b;
}

假设我们有两个线程。让第一个线程在调用 lock() 之前将变量 var 读取到寄存器,第二个线程在调用 lock() 之前将变量 var 读取到寄存器。然后第一个线程更改 var 但第二个线程看不到更改,因为它将值保留在寄存器中。这种非常糟糕的情况会发生吗?

我的意思是,通常只有局部变量会以这种方式进行优化:它们被放入寄存器,然后从那里读取,而不是从主内存中读取。据我了解,不应该以这种方式优化全局变量。但是静态局部变量呢?

【问题讨论】:

  • "...这种糟糕的情况会发生吗?..." - 是的。 std::mutex 的同步效果是 unlock() synchronizes-with lock()。但是您说的是在 lock() 之前使用对象 互斥锁提供的唯一保证是,lock()-unlock() 序列中的线程 Abar 的修改将是可见的到另一个线程,BB lock()s 互斥体之后。
  • 您需要在使用之前锁定资源,否则其他线程可能会在分配和锁定之间锁定它,从而导致竞争条件
  • @WhiZTiM C++11 不保证线程安全的静态?
  • @BiagioFesta,确实如此... OP 的问题与bar 的初始化无关。这是关于在锁定互斥体之前使用bar

标签: c++ multithreading static local compiler-optimization


【解决方案1】:

静态局部变量有一个全局变量的生命周期,它只有一个函数范围。您必须像使用适当的全局变量(互斥/原子)一样保护它。

注意:如果您在多个线程中使用任何种类的变量(我的意思是当线程使用相同的变量时),那么您必须使其线程安全。即使它是一个全局变量。即使变量存储在内存中。将变量存储在内存中并不能使其成为线程安全的。线程安全是一个问题,不是因为某些变量可能在寄存器中。可能有一个 CPU,其中不同的内核不会自动同步它们的缓存。因此,对于一个变量,每个内核的缓存中可能有多个值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-04-23
    相关资源
    最近更新 更多