【问题标题】:Wrapping an atomic type and ensuring that it remains atomic包装原子类型并确保它保持原子
【发布时间】:2019-07-15 04:39:53
【问题描述】:

我有一个有点独特和有趣(和可怕)的场景,它迫使我做一些棘手的事情。问题如下:

  1. 我们需要一种原子类型来在实时线程和后台加载线程之间进行无锁同步。
  2. 类型(不幸的是)必须编译:

    一个。 QNX只有c++03,但支持boost::atomic

    b.具有 c++11 但无法构建的 Nucleus boost::atomic

这迫使我考虑同时使用boost::atomicstd::atomic。我解决这个问题的方法是生成一个新类型,将所有功能转发到平台上的相关atomic 类型。这个想法是这样的:


Atomic.hpp

namespace osal { namespace detail {

template <typename T, template <class> class TAtomic >
struct AtomicImpl {

    void store(T desired, memory_order order = osal::memory_order_seq_cst) 
    {
        _atomic.store(desired, order);
    }

    // ... Other api

private:

    AtomicImpl& operator=(const AtomicImpl& rhs);
    // ... Other blocked operations
    TAtomic<T> _atomic;
};

}}


#if defined QNX
    #include <osal/QNX/Atomic.hpp>
#elif defined NUCLEUS
    #include <osal/NUCLEUS/Atomic.hpp>
#endif

这列出了一个类,该类将使用正确的 API 转发到 atomic 类型。幸运的是,booststd 实现几乎完全匹配。


然后在每个单独的操作系统文件中,如下所示:

Nucleus/Atomic.hpp

#include <atomic>

namespace osal 
{ 

template <typename T> struct atomic
   {
      typedef detail::AtomicImpl<T, std::atomic> type;
   };
}

这将创建带有std::atomic 的原子类型,允许使用如下:

osal::atomic<uint8_t>::type a;
a.store(1);

为了处理内存顺序的概念,存在一个类似的系统,其中包含一个文件,可以使用预处理器委托给每个操作系统实现。在实现中,例如。 Nucleus,我们有这个:

Nucleus/MemoryOrder.hpp

#include <memory>
namespace osal {

using std::memory_order;
using std::memory_order_relaxed;
...
}

显然,等效的using boost::... 将在 QNX 文件中(幸运的是它们再次匹配!)。

问题

这似乎有效。我可以制作一个原子并对其进行操作。我有一个顾虑:

这还是原子的吗?

既然我们已经在 API 中引入了间接,那么对原子对象的调用顺序会不会有问题?

作为一个额外的问题,考虑到限制,有没有更好的方法来做到这一点?

【问题讨论】:

  • w.r.t. atomic (没有那么多memoryorder)你可以查看生成的代码,看看它是否实际上是原子的。 (这样做时可能使用最严格的记忆顺序。
  • 这些库不能利用 API 本身的任何编译器魔法,所以只要你的 API 与两个库中使用的类型相同,我看不出它不应该工作的原因.添加一个函数调用层在原子性方面应该没有任何作用。
  • @MaxLanghof 我是这么认为的,我还认为即使外围操作不是原子的,也没关系,因为内部调用是。但我想检查一下。
  • 肯定会的。另一方面,它比维护自己的包装更省力。我还可以考虑中间解决方案,例如为从 std::atomic 或 boost::atomic 公开继承的 atomic 定义包装器。我很确定你的解决方案是安全的,但它看起来太冗长了。
  • @AlexanderGutenev 从std::atomic 继承不是一个好主意,它没有虚拟析构函数,如果人们将它用作std 类型指针,可能会导致非常糟糕的事情发生。我认为封装 API 并没有那么糟糕,它给了我们一点灵活性。

标签: c++ multithreading c++11 boost thread-safety


【解决方案1】:

具有 c++11 但无法构建的 Nucleus boost::atomic

boost::atomic&lt;T&gt; 类型是header-only,你可以使用它而无需构建boost::atomic 库。

您可以在两个平台上直接无条件地使用boost::atomic&lt;T&gt;(前提是您的平台受支持)。

有一些boost::atomic 库需要构建,请参阅https://github.com/boostorg/atomic 中的srctest 目录,但是,使用boost::atomic&lt;T&gt; 不需要这些。

【讨论】:

  • 这是对不同方法的建议吗?你能澄清一下吗?这是否是一个答案还不是很清楚。
  • @FantasticMrFox 只需使用boost::atomic&lt;T&gt;
  • 所以有一个 Nucleus 团队,当我说为什么这不起作用时,他们说 它就是不起作用,所以请使用 std::atomic。我不确定boost::atomic 是什么,但我们无法构建或运行单元测试套件。因此,我们无法检查它是否真正起作用。
  • @FantasticMrFox 我会尝试从该团队获得技术答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-12-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多