有人如何在一个线程中锁定多个对象?

时间:2017-10-21 22:46:28

标签: c++ multithreading

我正在尝试创建一个物理引擎(只是为了好玩),我希望它是多线程的 我理解互斥的基础知识(只有一个线程可以修改它一次保护的资源,它们应该是类级别而不是线程级别等)。我宁愿不使用原子作为成员变量(因此,如果我对它们进行复杂操作,它们将不会在执行过程中正确更改),或者只是复制变量(希望更低的内存占用) )。

遵循这个概念,(简化的)矢量类可能如下所示:

import ast
df['finally'] = df['finally'].apply(ast.literal_eval)

如果我想使用它,它们应该如何锁定?

class vector
{
    float x_, y_;
    std::mutex guard_;
};

喜欢这个?这实际上会保护这两个对象吗?

TL; DR当同一个线程操作多个对象时,如何锁定互斥锁? (不使用原子或制作副本)

2 个答案:

答案 0 :(得分:5)

std::lock_guard<std::mutex>(v1.guard_);
std::lock_guard<std::mutex>(v2.guard_);

这样,如果另一个线程试图以不同的顺序锁定相同的两个互斥锁,则存在死锁的风险。

为了避免死锁并确保异常安全,您需要先立即锁定两个互斥锁,然后将已锁定的互斥锁传递给采用构造函数的lock_guard

std::lock(v1.guard_, v2.guard_);
std::lock_guard<std::mutex> guard1(v1.guard_, std::adopt_lock);
std::lock_guard<std::mutex> guard2(v2.guard_, std::adopt_lock);

在C ++ 17中,您可以使用std::scoped_lock,类似std::lock_guard的类,但能够拥有多个互斥锁:

std::scoped_lock guard{v1.guard_, v2.guard_};

答案 1 :(得分:3)

你所写的内容很好,有一个臭名昭着的警告:如果两个线程试图采用相同的两个锁但是按相反的顺序,你将会死锁。经典dining philosophers问题说明了这一点。

标准解决方案是在锁上施加一些固定的任意顺序,并在所有情况下首先取下“下”。 user3290797的答案提供了用于执行此操作的正确库设施。