C++98 中关于 __sync_synchronize() 问题的 C++0x 原子实现

标签 c++ templates c++11 atomic

我编写了以下原子模板,以模仿即将推出的 c++0x 标准中可用的原子操作。

但是,我不确定围绕返回基础值进行的 __sync_synchronize() 调用是否必要。

根据我的理解,__sync_synchronize() 是一个完整的内存屏障,我不确定在返回对象值时是否需要如此昂贵的调用。

我很确定围绕值的设置需要它,但我也可以用程序集实现它..

__asm__ __volatile__ ( "rep;nop": : :"memory" );

有谁知道我是否确实需要在返回对象时使用 synchronize()。

M.

template < typename T >
struct atomic
{
private:
    volatile T obj;

public:
    atomic( const T & t ) :
        obj( t )
    {
    }

    inline operator T()
    {
        __sync_synchronize();   // Not sure this is overkill
        return obj;
    }

    inline atomic< T > & operator=( T val )
    {
        __sync_synchronize();   // Not sure if this is overkill
        obj = val;
        return *this;
    }

    inline T operator++()
    {
        return __sync_add_and_fetch( &obj, (T)1 );
    }

    inline T operator++( int )
    {
        return __sync_fetch_and_add( &obj, (T)1 );
    }

    inline T operator+=( T val )
    {
        return __sync_add_and_fetch( &obj, val );
    }

    inline T operator--()
    {
        return __sync_sub_and_fetch( &obj, (T)1 );
    }

    inline T operator--( int )
    {
        return __sync_fetch_and_sub( &obj, (T)1 );
    }

    inline T operator-=( T )
    {
        return __sync_sub_and_fetch( &obj, val );
    }

    // Perform an atomic CAS operation
    // returning the value before the operation
    inline T exchange( T oldVal, T newVal )
    {
        return __sync_val_compare_and_swap( &obj, oldval, newval );
    }

};

更新:我想确保操作在面对由于编译器优化而导致的读/写重新排序时是一致的。

最佳答案

首先,一些小的评论:

volatile T obj;

volatile在这里是没有用的,更何况所有的barrier都是你自己做的。

inline T operator++( int )

不需要内联,因为在类内部定义方法时会隐含内联。

getter 和 setter:

inline operator T()
{
    __sync_synchronize();   // (I)
    T tmp=obj;
    __sync_synchronize();   // (II)
    return tmp;
}

inline atomic< T > & operator=( T val )
{
    __sync_synchronize();   // (III)
    obj = val;
    __sync_synchronize();   // (IV)
    return *this;
}

为了确保读取和写入时内存访问的总顺序,每次访问都需要两个屏障(像这样)。我会很高兴只有障碍 (II) 和 (III),因为它们足以满足我想出的某些用途(例如,指针/ bool 值表示数据在那里,自旋锁),但是,除非另有说明,否则我不会省略其他,因为有人可能需要它们(如果有人表明您可以省略一些障碍而不限制可能的用途,那会很好,但我认为这是不可能的)。

当然,这会不必要地复杂和缓慢。

也就是说,我会放弃障碍,甚至是在类似模板的任何地方使用障碍的想法。请注意:

  • 该接口(interface)的排序语义全部由您定义;如果你决定界面在这里或那里有障碍,他们必须在这里或那里,期间。如果您不定义它,您可以提出更有效的设计,因为对于特定问题可能不需要所有障碍,甚至不是全部障碍。
  • 通常,如果你有一个可以给你带来性能优势的无锁算法,你就可以使用原子;这意味着过早地使访问变得悲观的接口(interface)可能无法用作它的构建 block ,因为它会妨碍性能本身。
  • 无锁算法通常包含无法由一种原子数据类型封装的通信,因此您需要知道算法中发生了什么,以便将屏障精确地放置在它们所属的位置(例如,在实现锁时,您需要一个屏障你获得它之后,但是你释放它之前,这都是写入,至少在原则上是这样)
  • 如果您不想遇到问题,并且不确定在算法中明确设置障碍,只需使用基于锁的算法。没什么不好的。

顺便说一句,c++0x 接口(interface)允许您指定精确的内存排序约束。

关于C++98 中关于 __sync_synchronize() 问题的 C++0x 原子实现,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2423567/

相关文章:

c++ - ISO C++ 禁止声明 .. 没有设置 --std=c++0x 的类型

c++ - 特征类、命名空间和前向声明

c++ - 没有匹配函数调用 "qsort"

C++动态模板创建

c++ - 如何在 C++ 中比较两个泛型类型?

C++11 在类中放置枚举类的重载运算符

c++ - 根据封闭类模板参数有条件地定义嵌套类

c++ - 红黑树——删除

c++ - 如何在 Windows 上将无效的 fgetpos 调用捕获为 C++ 异常?

html - 为网站的不同页面制作 CSS 样式表