我正在尝试创建一个物理引擎(只是为了好玩),我希望它是多线程的 我理解互斥的基础知识(只有一个线程可以修改它一次保护的资源,它们应该是类级别而不是线程级别等)。我宁愿不使用原子作为成员变量(因此,如果我对它们进行复杂操作,它们将不会在执行过程中正确更改),或者只是复制变量(希望更低的内存占用) )。
遵循这个概念,(简化的)矢量类可能如下所示:
import ast
df['finally'] = df['finally'].apply(ast.literal_eval)
如果我想使用它,它们应该如何锁定?
class vector
{
float x_, y_;
std::mutex guard_;
};
喜欢这个?这实际上会保护这两个对象吗?
TL; DR当同一个线程操作多个对象时,如何锁定互斥锁? (不使用原子或制作副本)
答案 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的答案提供了用于执行此操作的正确库设施。