从线程调用原子数据成员

Posted

技术标签:

【中文标题】从线程调用原子数据成员【英文标题】:Atomic data member calling from a thread 【发布时间】:2016-12-22 00:08:17 【问题描述】:

有人可以帮我理解我在这里做错了什么吗? 当我将类的数据成员设为非原子时,它工作正常。

class AtomicTest

    atomic<int> A 0 ;
    atomic<int> B 0 ;
public :
    AtomicTest()   
    void func1()
    
        A = 1;
        cout << "func1 " << A << endl;;
    
    void func2()
    
        cout << "func2 " << A << endl;
        A = A + 1;
        cout << A << endl;
    
;

int main()

    AtomicTest a;
    thread t1(&AtomicTest::func1, std::ref(a)); // I tried to move as well, i know ref would share data between two threads but i can use mutex to protect data if its needed but i cannot even call the func1

    //thread t2(&AtomicTest::func2, std::ref(a));
    t1.join();
    //t2.join();

    return 0;

【问题讨论】:

我想你没试过:std::bind(&amp;AtomicTest::func1, std::ref(a)) 作为线程构造函数的唯一参数? 我肯定没有,因为我不知道为什么它会这样工作。我可以知道为什么它不能那样工作,而是使用绑定吗? 有人能告诉我问题是什么吗?使用 clang 对我来说效果很好。 @DietmarKühl 不适合我。我使用的是 clang 3.8(苹果的端口),它在attempt to invoke a deleted constructor 上呕吐。通过std::bind 扭转它或简单地使用&amp;a 作为第二个参数可以消除错误。顺便说一句,节日快乐。 @WhozCraig:clang-3.9 似乎解决了这个问题。当然,代码确实编译的问题,例如因为它缺少必要的包含指令。 【参考方案1】:

由于在这种情况下没有额外同步的并发性,无法预测程序行为:

A = A + 1;

这个简单的行包含 1 个原子 load 和 1 个原子 store 操作。即使是默认内存顺序 (std::memory_order_seq_cst) 也不能为您提供关于这两个线程的混合同时执行的任何保证。标准说这种情况有一个未定义的行为——你的变量存在数据竞争(不管是不是atomic)。

尝试添加一些锁原语(如std::mutex)或更改逻辑以使用特殊的原子函数(如fetch_addexchange等)。在cpp-reference 上查看更多信息。

【讨论】:

我知道互斥体,并且我知道数据竞争条件。我所担心的是为什么那个线程调用没有运行。我提到的和评论一样。不过,我不知道 fetch_add 和 exchange。感谢您的信息 对不起,也许我没有理解确切的问题,使代码工作的明显方法是检查include 并使用--std=c++11 指令。顺便说一句(带有必要的包含、指令和库),它可以编译并适用于所有现代编译器(参见这个不错的 tool)。

以上是关于从线程调用原子数据成员的主要内容,如果未能解决你的问题,请参考以下文章

mmap 是原子的吗?

多线程编程之原子锁

在破坏调用期间从另一个线程未定义的行为调用对象上的方法?

STL的线程安全解决方案

当锁定不可用时,调用Lock.lock()的线程何时从调用返回?

SQL Server 触发器内的存储过程调用是不是隐含线程安全和原子?