原子类对象方法用法

Atomic class object methods usage

本文关键字:用法 方法 对象 子类      更新时间:2023-10-16

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

主线程:

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 调用方法之前使用互斥锁和锁定,在调用方法后解锁)?

不能将std::atomic用于不可复制的用户定义类型,并且标准仅为某些基本类型提供了一组有限的专用化。在这里,您可以找到std::atomic所有标准专业的列表。

您可能需要考虑的一种方法是编写一个通用包装器,该包装器允许您提供可调用的对象,以便在包装的对象上以线程安全的方式执行。赫伯·萨特(Herb Sutter)曾经在他的一次演讲中提出了类似的东西:

template<typename T>
class synchronized
{
public:
    template<typename... Args>
    synchronized(Args&&... args) : _obj{std::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);
    });
}

有关更深入的分析和实施指南,您可以参考有关该主题的这篇文章以及本文。

在不同的线程之间共享一个std::mutex。无论您在哪里使用foo,请用std::unique_lock包装呼叫