C++ 除了数据竞争之外,同步读/写是否会导致其他问题?

C++ 除了数据竞争之外,同步读/写是否会导致其他问题?,c++,multithreading,C++,Multithreading,我的理解是,当两个线程同时读写同一个变量时,应用程序会崩溃。我写了一个小程序来模拟这个场景。我运行了几次,但没有发现任何崩溃。我错过了什么 #include <iostream> #include <thread> using namespace std; int g_TestVar = 0; void ReadFunction() { for (size_t i = 0; i < 5000; ++i) { cout <<

我的理解是,当两个线程同时读写同一个变量时,应用程序会崩溃。我写了一个小程序来模拟这个场景。我运行了几次,但没有发现任何崩溃。我错过了什么

#include <iostream>
#include <thread>

using namespace std;

int g_TestVar = 0;

void ReadFunction()
{
    for (size_t i = 0; i < 5000; ++i) {
        cout << this_thread::get_id() << "------" << g_TestVar << '\n';
    }
}

void WriteFunction()
{
    for (size_t i = 0; i < 5000; ++i) {
        g_TestVar = rand();
    }
}

int main()
{
    thread ReadThread[100];
    thread WriteThread[100];

    for (size_t i = 0; i < 100; ++i) {
        ReadThread[i] = thread(ReadFunction);
        WriteThread[i] = thread(WriteFunction);
    }

    for (size_t i = 0; i < 100; ++i) {
        ReadThread[i].join();
        WriteThread[i].join();
    }

    return 0;
}
#包括
#包括
使用名称空间std;
int g_TestVar=0;
void ReadFunction()
{
对于(尺寸i=0;i<5000;++i){

cout正如Jerry Coffin所提到的,你得到了。然而,并非所有UB都意味着你会得到崩溃。崩溃通常是因为两件事发生的:

  • 读取/写入未映射到程序内存空间的内存位置
  • 执行无效指令
由于线程正在执行有效代码,并且从程序内存空间内的变量读取/写入,因此不会出现崩溃。这是UB,因为无法保证
g_TestVar
将以原子方式写入或读取,尽管您只是向其写入随机值,这一点都不重要嗯


程序不崩溃的问题当然是,未定义的行为并不明显,可能会给你一种错误的感觉,认为有一个正确的程序。有一些工具,如,和编译器选项,可能会帮助你找到一些UB形式。

你关于程序崩溃的假设,因为读写一致从/到变量的顺序错误


关于原子性…对变量的读写操作可以是原子的,相互独立,但这取决于体系结构,因此没有保证。感谢其他贡献者向我澄清这一点。

您应该将变量
g_TestVar
设置为如下原子变量:

#include <atomic>

std::atomic<int> g_TestVar = 0;
#包括
std::原子g_TestVar=0;
这将确保每个线程都有对变量的原子访问权。否则它是未定义的行为(不一定是崩溃)

你必须记住,在你的源代码和实际的机器指令之间有很多层。硬件也包括缓存。所有这些东西都可以对内存读写进行重新排序。你所关心的只是你的程序以顺序交错的方式执行,但你的编译器不知道共享什么数据线程之间。因此,读取和写入可能不会按照您想要的顺序进行


如果使用原子变量或互斥体,则会创建一个屏障或围栏,告知硬件隔离执行某些操作。

线程竞相读取和写入变量时,我可以想到三个问题:

  • 如果变量大于字长,则变量可能在读取时被部分写入。这意味着读取将报告错误值
  • 如果全局变量是在同一线程中写入而不是读取的,编译器可能会决定优化该值
  • 即使是易失性的,一些处理器也可能会对读写进行重新排序,如果写入顺序很重要,这可能会导致问题

  • 你没有得到明确的行为。无法保证在这种情况下会发生什么。获得错误数据的可能性很高。实际崩溃的几率要低得多(事实上,我会考虑一个实际的崩溃,这是硬件设计失败的一个很强的迹象)。“除此之外,林肯夫人,你觉得这出戏怎么样?"C++不保证登记> int >代码>读写是原子的。例如,即使你只能用一个指令读写,也不能保证实际的读/存储到内存是原子的。例如,内存总线宽度可能小于CPU的寄存器宽度,因此需要多个总线周期。e
    int
    。如果在多周期访问期间无法锁定总线,则无法保证原子性。这还取决于变量是否正确对齐。x86 AVX加载/存储指令非常大,并不总是原子的,请参见示例。根据您的澄清更正了我的答案。谢谢。