包装一个原子类型并确保它仍然是原子

时间:2019-02-21 09:55:51

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

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

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

    a。 QNX仅具有c ++ 03,但支持boost::atomic

    b。具有c ++ 11但无法构建boost::atomic

  3. 的Nucleus

这迫使我考虑同时使用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实现几乎完全匹配。


然后在每个单独的OS文件中,如下所示:

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);

为了处理内存顺序的概念,存在一个类似的系统,该系统带有一个文件,用于使用预处理器委派给每个OS实现。在实施中,例如核,我们有这个:

Nucleus / MemoryOrder.hpp

#include <memory>
namespace osal {

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

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

问题

这似乎起作用。我可以做一个原子并对其进行操作。我担心:

这仍然是原子的吗?

现在我们在API中引入了间接寻址,对原子对象的调用顺序是否会出现问题?

作为奖励问题,考虑到约束条件,是否有更好的方法来做到这一点?

1 个答案:

答案 0 :(得分:0)

  

具有c ++ 11但不能构建boost::atomic

的核

boost::atomic<T>类型仅是标题,您可以使用它而无需构建boost::atomic库。

您可以在两个平台上直接无条件使用boost::atomic<T>(前提是支持您的平台)。

boost::atomic库中有一些地方需要构建,请参见https://github.com/boostorg/atomic中的srctest目录,但是,使用boost::atomic<T>并不需要需要那些。