是否是线程安全的,当它在主线程中填充数据时,从结构数组的较低索引元素读取

yek*_*chi 3 c++ multithreading producer-consumer stdatomic

原始问题:

我得到了一个结构数组,并在主线程中读取它时将其填充到一个单独的线程中:

struct DataModel MyData[1024];

struct DataModel
{
    bool IsFilled;
    float a;
    float b;
}
Run Code Online (Sandbox Code Playgroud)
  • 我有一个Thread,它将Mydata数组从0索引填充到最后一个索引(在上面是1024).

  • 然后我从填充线程中获取最后一个填充的结构索引.

  • 然后我尝试读取元素的值,其中一个索引低于填充的索引.

  • 我们假设当第500个元素被填充时,我从MyData数组的499元素中读取值,所以我确保我没有读取正在写入的数组元素.

Q1:这个线程安全吗?

Q2:是否有可能发生未定义的行为或误读vales?


进一步编辑:

问题是编辑不当以添加更多细节,这就是为什么它引入了不一致的答案,所以我分开了以前的编辑,以提高答案和接受答案的一致性.

编辑1:这是可能实施的建议.虽然它可能显示错误的结果,但只是我想询问线程安全和未定义的行为,以下解决方案可能会显示各种结果,但我试图首先询问线程安全性.

std::atomic<int> FilledIndex;
    void FillingMyData(struct DataModel myData[])
    {
      for(size_t i = 0; i < 1024; i++)
      {
        myData[i].a = rand();
        myData[i].b = rand();
        myData[i].IsFilled = true;

    FilledIndex = i;
  }
}

int main()
{
     std::thread ReadThread(FillingMyData, MyData);
     while(FilledIndex < 1024)
     {
          std::cout << MyData[FilledIndex].a;
     }
     ReadThread.join();
     return 0;
}
Run Code Online (Sandbox Code Playgroud)

Nat*_*ica 8

是的,可以安全地处理同一阵列中的单独对象.即使数组是一个对象,它也是我们正在处理的数组元素,它们是单独的对象.只要您没有读取编写器正在写入的元素,就没有数据争用,并且代码已定义了行为.您的已发布代码确实存在同步问题,但此处的其他答案涵盖了这些问题.

这里可能发生的是所谓的虚假共享.在这些情况下会发生的情况是,单独的对象位于内存中的同一缓存行中.当核心/线程更改一个对象时,该缓存行被标记为已更改.这意味着另一个核心/线程必须重新同步该行以引入任何更改,这意味着两个核心/线程不能同时运行.这只是性能损失,程序仍会给出正确的结果,它会慢一点.

  • @yekanchi嗯,问题中描述的解决方案不需要`std :: atomic <bool>`.为了传递准备读取的索引,有许多可能的解决方案,`std :: atomic <std :: size_t>`是其中之一,但不是唯一的解决方案. (3认同)