原子类对象方法用法

Posted

技术标签:

【中文标题】原子类对象方法用法【英文标题】:Atomic class object methods usage 【发布时间】:2015-01-20 17:23:53 【问题描述】:

我想从两个线程原子地调用某个类的方法。 我有来自第三方库的非头部安全类,但需要像这样使用这个类:

主线程:

Foo foo;
foo.method1(); // while calling Foo::method1 object foo is locked for another threads

第二个线程:

foo.method2(); // wait while somewere calling another methods from foo

在这种情况下如何使用 std::atomic ?或者可能是另一种解决方案(排除在调用 foo 方法之前使用互斥锁和解锁)?

【问题讨论】:

【参考方案1】:

您不能将std::atomic 与不可简单复制的用户定义类型一起使用,并且该标准仅为某些基本类型提供了一组有限的特化。 Here 你可以找到std::atomic 的所有标准专业列表。

您可能要考虑的一种方法是编写一个通用包装器,它允许您提供可调用对象,以便在包装对象上以线程安全的方式执行。 Herb Sutter 曾经在one of his talks 中提出过类似的内容:

template<typename T>
class synchronized

public:
    template<typename... Args>
    synchronized(Args&&... args) : _objstd::forward<Args>(args)...  

    template<typename F>
    void thread_safe_invoke(F&& f)
    
        std::lock_guard<std::mutex> lock_m;
        (std::forward<F>(f))(_obj);
    

    // ...

private:
    T _obj;
    std::mutex _m;
;

如果您只想以线程安全的方式调用单个函数,这会产生一些语法开销,但它也允许实现必须以原子方式执行的事务,并且可能包含对同步对象的多个函数调用。

你可以这样使用它:

int main()

    synchronized<std::string> s"Hello";

    s.thread_safe_invoke([&] (auto& s)
    
        std::cout << s.size() << " " << (s + s);
    );

如需更深入的分析和实施指导,您可以参考该主题的this article以及this one。

【讨论】:

【参考方案2】:

在不同线程之间共享std::mutex。无论您在哪里使用foo,都可以使用std::unique_lock 包装调用

【讨论】:

另一种解决方案?使用互斥锁是可以的,但需要更多的代码行(每次调用 1-2 行)。 @Anton 你可以将Foo 包装在一个SynchronisedFoo 类中,如果冗长是一个普遍的问题,它会为它包装的每个方法锁定一个互斥锁。

以上是关于原子类对象方法用法的主要内容,如果未能解决你的问题,请参考以下文章

Juc15_基本AtomicInteger数组引用AtomicStampedReference对象的属性修改原子类AtomicIntegerFieldUp 原子操作增强类LongAdder

Java并发AtomicReference类

原子性与锁

创建一个对象和i++是否原子性的理解

类方法的用法

Python()- 面向对象的组合用法