繁体   English   中英

任意大小数据/向量/数组的原子和无锁写入

[英]Atomic and lock-free write of arbitrary sized data/vector/array

我正在尝试实现以下功能:

  • 具有任意大小的数据类型的原子和无锁写入或读取-修改-写入(在我的情况下通常是具有最多 6 个元素的 float/int 向量)。
  • 从不阻塞写入线程的上述数据类型进行原子读取。 读操作可能被写操作阻塞。

用例:我正在尝试为 CNC 机床编写软件。 电机的步进脉冲由软件在实时线程中生成。 该实时线程不断更新保存轴当前位置的变量。 多个其他非实时线程可以读取该变量,例如显示当前位置。

问题 1:对于此类问题,是否有标准/公认的解决方案或模式?

我想出了以下想法:使用std::atomic<uint64_t>来保护数据并跟踪线程当前正在写入的天气(通过检查最后一位)或自读取开始以来已写入的天气(通过增加写)。

template <class DATA, class FN>
void read_modify_write(DATA& data, std::atomic<uint64_t>& protector, FN fn)
{
  auto old_protector_value = protector.load();
  do
  {
    // wait until no other thread is writing
    while(old_protector_value % 2 != 0)
      old_protector_value = protector.load();

    // try to acquire write privileges
  } while(!protector.compare_exchange_weak(old_protector_value, old_protector_value + 1));

  // write data
  data = fn(data);

  // unlock
  protector = old_protector_value + 2;
};

template <class DATA>
DATA read(const DATA& data, std::atomic<uint64_t>& protector)
{
  while(true)
  {
    uint64_t old_protector_value = protector.load();

    // wait until no thread is writing
    while(old_protector_value % 2 != 0)
      old_protector_value = protector.load();

    // read data
    auto ret = data;

    // check if data has changed in the meantime
    if(old_protector_value == protector)
      return ret;
  }
}

问题2:以上代码是否线程安全并满足上述要求?

问题三:可以改进吗?

(我能找到的唯一理论问题是计数器是否回绕,即在 1 次读取操作期间执行了 2^63 次写入操作。如果没有更好的解决方案,我认为这个弱点是可以接受的。)

谢谢

严格来说,您的代码不是无锁的,因为您有效地使用了protector的 LSB 来实现自旋锁。

您的解决方案看起来非常像一个序列锁 但是,实际的读操作auto ret = data; 严格来说是数据竞赛。 公平地说,根本不可能在 C++17 中编写完全符合标准的 seqlock,为此我们必须等待 C++20。

可以扩展 seqlock 以使读取操作无锁,但代价是更高的内存使用量。 这个想法是拥有数据的多个实例(让我们称它们为槽),并且写操作总是以循环方式写入下一个槽。 这允许读取操作从最后一个完全写入的插槽中读取。 Dmitry Vyukov 在改进的 Lockfree SeqLock 中描述了他的方法。 您可以查看我的seqlock 实现,它是我的xenium库的一部分。 它还可选地允许具有可配置插槽数的无锁读取操作(尽管它与 Vyukov 在阅读器如何找到最后一个完全写入的插槽方面略有不同)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM