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

Dmi*_*try 1 c++ multithreading

假设我有 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;
}
Run Code Online (Sandbox Code Playgroud)

线程 thd2 定期读取此标志

std::int32_t getFlag()
{
   //std::lock_guard<std::mutex> lk(io_mutex);
   return g_flag;
}
Run Code Online (Sandbox Code Playgroud)

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

wal*_*nut 5

访问内存位置以在一个线程中进行写入以及在没有同步的情况下在另一个线程中进行读取或写入,并且至少其中一个是非原子的,这被称为数据竞争,并会导致 C++ 中的未定义行为。

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

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

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

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

std::atomic<std::int32_t> g_flag{};
Run Code Online (Sandbox Code Playgroud)

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

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

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

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