对全局变量的多线程访问:我应该使用互斥锁吗?



假设我有2个线程:std::thread thd1; std::thread thd2;线程 thd1 周期性地设置一些全局变量调用以下setFlag函数:

static std::int32_t g_flag;
static std::mutex io_mutex;
void setFlag( std::int32_t flag )
{
//std::lock_guard<std::mutex> lk(io_mutex);
g_flag = flag;
}

线程 thd2 定期读取此标志

std::int32_t getFlag()
{
//std::lock_guard<std::mutex> lk(io_mutex);
return g_flag;
}

问题是 - 在这种情况下我应该使用互斥锁吗?在没有互斥锁的情况下,从多个线程以读写方式访问变量是否安全?

访问一个线程中的写入和另一个线程中的读取或写入而不同步的内存位置,并且至少其中一个是非原子的,这称为数据争用,并导致C++中未定义的行为。

在代码中,对线程 1g_flag的写入访问权限与线程 2 对同一变量的读取访问权限不同步。

因此,您的程序具有未定义的行为(因为没有任何访问是原子的(。

一种可能的解决方案是在注释代码中正确演示时使用互斥锁,这将同步读取和写入访问,以便一个发生在另一个之前,尽管这些发生之前的顺序仍然不确定。

另一种可能性是将g_flag声明为原子:

std::atomic<std::int32_t> g_flag{};

如上所述,原子访问(std::atomic提供(在可能并行访问以进行写入和读取时特别免于导致数据争用和未定义的行为。

原子(通常(不会像互斥锁/锁那样使另一个线程等待。但是,如果您还要访问其他共享内存,这也会使正确使用变得更加棘手。

相反,std::atomic还有进一步的选项来指定是否以及如何对原子访问周围的其他内存访问进行排序,即它是否以及在多大程度上也会导致线程之间的同步。

如果没有进一步的细节,我无法确定在您的情况下合适的工具是什么。

最新更新