推理包含数据竞争的程序

Vis*_*rma 3 c++ c++14 data-race

这个问题是我上一个问题的延续,我的理解是“ A data race is a property of an execution, not of the program in the abstract”,这意味着只要 2 个线程不访问共享变量(至少有一个是写访问),实际上而不仅仅是理论上,那么程序的行为将得到很好的定义。

根据上述理解,我想讨论以下方案:

#include <iostream>
#include <thread>
#include <unistd.h>

constexpr int sleepTime = 10;

void func(int* ptr) {
    sleep(sleepTime);
    std::cout<<"going to delete ptr: "<<(uintptr_t)ptr<<"\n";
    delete ptr;
    std::cout<<"ptr has been deleted\n";
}

int main() {

    int* l_ptr = new int(5);

    std::thread t(func, l_ptr);

    t.detach();


    std::cout<<"We have passed ptr: "<<(uintptr_t)l_ptr<<" to thread for deletion. Val at ptr: "<<*l_ptr<<"\n";

    std::cin.get();

}
Run Code Online (Sandbox Code Playgroud)

上面的程序包含数据竞争,当且仅当“主线程”和“子线程”碰巧同时访问共享变量时。

然而,至少可以合理地说,在使用多核 CPU时,这种情况在现实中极不可能发生。

Cal*_*eth 10

上面的程序包含一个数据竞争,句号。

两个线程上对同一对象的访问彼此不排序。这不是“同时”的问题。

该标准定义了一个关系Happens-Before,它只与事情发生时的挂钟时间几乎没有关系。

未定义的行为并不意味着“观察到发生了不好的事情”。这意味着您无法根据 C++ 规则推断您观察到的情况。

  • @VishalSharma您提供了一个程序,所有可能的执行都存在数据竞争 (6认同)
  • @VishalSharma“数据竞争”有严格的定义,可以归结为“两个线程访问一个非原子变量,至少其中一个正在写入它,并且两个访问都*发生在另一个之前”,其中“发生before”只能由互斥体、某些类型的原子操作等引起。睡眠不会导致“以前发生过”。 (6认同)
  • 顺便说一句,取消引用指针以查看它是否已在其他地方被删除并不是检测一个线程是否比另一个线程快的好方法,因为在它被删除的情况下这也是未定义的行为 (3认同)
  • @VishalSharma:因为数据竞争不仅仅是“同时”访问内容。 (2认同)

Nic*_*las 6

我的理解是“数据竞争是执行的一个属性,而不是抽象的程序的属性”,这意味着只要 2 个线程不访问共享变量(至少有一个是写访问),实际上而不仅仅是理论上,那么程序的行为将得到很好的定义。

你的理解是正确的。您对这种理解的应用不是:

上面的程序包含数据竞争,当且仅当“主线程”和“子线程”碰巧同时访问共享变量时。

数据竞争不是关于“同时访问共享变量”。它们是在没有适当同步的情况下访问内存,因此两次访问之间不存在“发生之前”关系。

在其他线程中删除指针和在主线程中使用它之间不存在这种关系。因此,这段代码存在数据竞争。该数据竞争是其执行的一个属性,并且该执行具有数据竞争,因为该执行不包含任何会阻止数据竞争发生的内容。它有两种访问,其中一种是写入,它们之间没有发生之前的顺序。

因此,存在数据竞争。

条件数据竞争看起来像这样:

#include <iostream>
#include <thread>
#include <unistd.h>
#include <atomic>

std::atomic<bool> flag = false;

constexpr int sleepTime = 10;

void func(int* ptr) {
    sleep(sleepTime);
    std::cout<<"going to delete ptr: "<<(uintptr_t)ptr<<"\n";
    delete ptr;
    flag = true;
    flag.notify_all();
    std::cout<<"ptr has been deleted\n";
}

int main() {

    int* l_ptr = new int(5);

    std::thread t(func, l_ptr);

    t.detach();

    int i = 0;
    std::cin >> i;
    if(i == 5)
    {
        test.wait(false);
    }

    std::cout<<"We have passed ptr: "<<(uintptr_t)l_ptr<<" to thread for deletion. Val at ptr: "<<*l_ptr<<"\n";

    std::cin.get();

}
Run Code Online (Sandbox Code Playgroud)

这将执行正确的同步,创建先发生关系,但仅当用户输入值“5”时才会执行此操作。如果他们输入其他内容,就会出现数据竞争。