2012-10-18 132 views
2

我在Windows XP上使用MinGW 4.6.2,并且遇到了std :: atomic的一些奇怪行为。 的情况如下:MinGW 4.6.2 std ::原子指针

  • 线程A创建了一个的std ::原子变量(以T *作为模板参数)。
  • 线程B修改它。
  • 线程A等待修改然后读取变量。

最终的结果是,通过线程A读出的值是不 - 一个通过螺纹B.

设置如果删除了的std ::原子(即保存该变量作为指针)它按预期工作。更有趣的是,如果我将模板参数设置为无符号长整数,并将指针指向和从 T *它按预期工作。

我使用赋值运算符来设置值和负载成员以获取值。

我是否缺少std :: atomic与T *作为参数应该工作还是这种破坏行为?

编辑

一些代码

#include <boost/thread.hpp> 
    #include <atomic> 

    using namespace std; 

    void* vptr; 
    std::atomic<unsigned int> aui; 
    std::atomic<void*> aptr; 

    void foo() 
    { 
     vptr = (void*) 0x123; 
     aui = (unsigned int) 0x123; 
     aptr = (void*) 0x123; 
    } 

    int main(int argc, char* argv[]) 
    { 
     boost::thread threadA; 

     vptr = nullptr; 
     aui = 0; 
     aptr = nullptr; 

     threadA = boost::thread(foo); 
     threadA.join(); 

     cout << vptr << " " << (void*)aui.load() << " " << aptr.load(); 

     return 0; 
    } 

输出是:0x123的0x123的0x41d028

+2

不要描述代码,发布它。 – GManNickG

+2

不要将指针指向'unsigned long'。使用'std :: uintptr_t',这就是它的用途。 – rubenvb

+0

“...如果我将模板参数设置为无符号长整型,并将指针指向T *并按照预期工作。” –

回答

2

我用MinGW 4.6.1重现了你的问题(并发现它固定在4.7.0)。如果您无法移动到解决问题的新MinGW,那么您应该可以修改lib/gcc/mingw32/4.6.2/include/c++/bits/atomic_0.h标头的_ATOMIC_STORE_宏的定义(假设4.6.2中的标头与4.6.1相似) :

#if 0 /* disable the original broken macro */ 
#define _ATOMIC_STORE_(__a, __n, __x)      \ 
    ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type;       \ 
    __i_type* __p = &_ATOMIC_MEMBER_;      \ 
    __typeof__(__n) __w = (__n);       \ 
    __atomic_flag_base* __g = __atomic_flag_for_address(__p);   \ 
    __atomic_flag_wait_explicit(__g, __x);     \ 
    *__p = __w;        \ 
    atomic_flag_clear_explicit(__g, __x);      \ 
    __w; }) 
#else 
#define _ATOMIC_STORE_(__a, __n, __x)      \ 
    ({typedef __typeof__(_ATOMIC_MEMBER_) __i_type;       \ 
    __i_type* __pxx = &_ATOMIC_MEMBER_;     \ 
    __typeof__(__n) __w = (__n);       \ 
    __atomic_flag_base* __g = __atomic_flag_for_address(__pxx);  \ 
    __atomic_flag_wait_explicit(__g, __x);     \ 
    *__pxx = __w;         \ 
    atomic_flag_clear_explicit(__g, __x);      \ 
    __w; }) 
#endif 

的问题似乎是在一个名为__p宏观,这显然会导致混乱当宏与可变还被评为__p为宏参数__n调用的局部变量。当__n扩展为__p时,扩展宏访问本地变量,而不是访问调用者'通过'的变量。