首页 > 解决方案 > 连续内存块中的 C++ 原子操作

问题描述

std::atomic在连续的内存块中分配值时,是否可以使用原子操作,可能使用库。

如果我有这个代码:

uint16_t* data = (uint16_t*) calloc(num_values, size);

我能做些什么来进行这样的原子操作:

data[i] = 5;

我将有多个线程同时分配给data,可能在同一个索引处。这些线程在特定索引处修改值的顺序对我来说并不重要,只要修改是原子的,避免任何可能的数据损坏。

编辑:所以,根据@user4581301,我在这里为我的问题提供了一些背景信息。我正在编写一个程序来将深度视频数据帧与彩色视频数据帧对齐。用于深度和颜色的相机传感器具有不同的焦点特性,因此它们不会完全对齐。一般算法涉及将深度空间中的像素投影到颜色空间中的区域,然后用该单个像素覆盖深度帧中跨越该区域的所有值。我正在并行化这个算法。这些投影区域可能会重叠,因此当并行化时,对索引的写入可能会同时发生。

伪代码如下所示:

for x in depth_video_width:
  for y in depth_video_height:
      pixel = get_pixel(x, y)
      x_min, x_max, y_min, y_max = project_depth_pixel(x, y)

      // iterate over projected region
      for x` in [x_min, x_max]:
         for y` in [y_min, y_max]:
             // possible concurrent modification here
             data[x`, y`] = pixel

外部循环或最外面的两个循环是并行的。

标签: c++

解决方案


您将无法像这样完全按照您的意愿行事。

原子数组没有多大意义,也不是您想要的(您希望单个写入是原子的)。

你可以有一个原子数组:

#include <atomic>
#include <array>

int main()
{
    std::array<std::atomic<uint16_t>, 5> data{};
    data[1] = 5;
}

…但现在你不能只访问一个连续的uint16_ts 块,这暗示着你想要这样做。

如果你不介意特定于平台的东西,你可以保留你的uint16_ts 数组并确保你只对每一个使用原子操作(例如GCC 的__atomic内在函数)。

但是,一般来说,我认为您会希望保持简单,并在访问普通数组时锁定互斥锁。测量以确保,但您可能会惊讶于您没有得到多少性能损失。

如果您急需原子,急需 的底层数组,急需uint16_t标准解决方案,您可以等待 C++20 并为每个元素保留一个std::atomic_ref(这就像非拥有),然后访问std::atomic通过这些元素。但是,您仍然必须对任何直接访问元素的操作保持谨慎,可能通过使用锁,或者至少要非常小心在做什么和何时做什么。此时您的代码要复杂得多:确保它是值得的。


推荐阅读