我有一个独特而有趣(可怕的)场景,迫使我做一些棘手的事情。问题如下:
- 我们需要一种原子类型才能在实时线程和背景加载线程之间进行无锁的同步。
-
类型(不幸的是)必须在:
上编译a。QNX仅具有C 03,但支持
boost::atomic
。b。具有C 11但无法构建
boost::atomic
的核
这迫使我考虑同时使用boost::atomic
和std::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
类型的类。幸运的是,boost
和std
实现几乎完全匹配。
然后在每个单个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/memoryordor.hpp
#include <memory>
namespace osal {
using std::memory_order;
using std::memory_order_relaxed;
...
}
显然,等效的using boost::...
将在QNX文件中(幸运的是它们再次匹配!)。
问题
这似乎有效。我可以做一个原子并对其进行操作。我很担心:
这仍然是原子吗?
现在我们已经在API中引入了间接,对原子对象的调用顺序是否存在问题?
作为限制,作为一个奖励问题,有更好的方法可以做到这一点吗?
具有C 11但无法构建
的核boost::atomic
boost::atomic<T>
类型是仅标题,您可以使用它而无需构建boost::atomic
库。
您可以在两个平台上直接和无条件地使用boost::atomic<T>
(前提是您的平台得到支持)。
有一些需要构建的boost::atomic
库,请参见https://github.com/boostorg/atomic中的src
和test
目录,但是,使用boost::atomic<T>
不需要这些。