【问题标题】:MinGW 4.6.2 std::atomic pointerMinGW 4.6.2 std::atomic 指针
【发布时间】:2012-10-18 16:32:07
【问题描述】:

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

  • 线程 A 创建一个 std::atomic 变量(以 T* 作为模板参数)。
  • 线程 B 对其进行了修改。
  • 线程 A 等待修改然后读取变量。

最终结果是线程A读取的值不是线程B设置的值。

如果我删除 std::atomic (将变量保存为指针),它会按预期工作。更有趣的是,如果我将模板参数设置为 unsigned long 并将指针与 T* 之间进行转换,它会按预期工作。

我正在使用赋值运算符来设置值和加载成员来获取值。

我是否错过了以 T* 作为参数的 std::atomic 应该如何工作,或者这是一种破坏行为?

编辑

一些代码

    #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

【问题讨论】:

  • 不要描述代码,贴出来。
  • 不要将指针投射到unsigned long。使用std::uintptr_t,这就是它的用途。
  • "...如果我将模板参数设置为 unsigned long 并将指针与 T* 之间进行转换,它会按预期工作。"

标签: c++ concurrency c++11 mingw


【解决方案1】:

我用 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 时,扩展的宏不会访问调用者“传入”的变量,而是访问局部变量。

【讨论】:

    【解决方案2】:

    这可能是http://gcc.gnu.org/bugzilla/show_bug.cgi?id=51811 - 在 GCC 4.7 中已修复

    你能显示导致问题的代码吗?

    【讨论】:

    • 只使用赋值运算符将原子赋值给一个值。
    猜你喜欢
    • 1970-01-01
    • 2012-03-22
    • 2020-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-19
    • 2017-05-28
    相关资源
    最近更新 更多