gpt4 book ai didi

How does std::lock work with std::unique_lock objects instead of directly with std::mutex?(Std::lock如何与std::Unique_lock对象一起工作,而不是直接与std::Mutex一起工作?)

转载 作者:bug小助手 更新时间:2023-10-26 21:12:35 24 4
gpt4 key购买 nike



I'm working with a piece of multithreading code that involves bank account transfers. The goal is to safely transfer money between accounts without running into race conditions. I'm using std::mutex to protect the bank account balances during transfers:

我正在使用一段涉及银行转账的多线程代码。目标是在账户之间安全地转账,而不会遇到竞争条件。我正在使用std::Mutex在转账过程中保护银行帐户余额:


My question centers around the use of std::unique_lock with std::lock. Instead of passing the std::mutex objects directly to std::lock, I'm wrapping them with std::unique_lock and passing those to std::lock.

我的问题集中在std::only_lock和std::lock的使用上。我不是将std::mutex对象直接传递给std::lock,而是用std::only_lock包装它们,并将它们传递给std::lock。


How does std::lock work with std::unique_lock objects?

Std::lock如何与std::Unique_Lock对象一起工作?


Is std::lock responsible for actually locking the from and to mutexes, while the std::unique_lock objects merely manage the locks (i.e., release them when they go out of scope)?

Std::lock是否负责实际锁定from和to互斥锁,而std::only_lock对象只是管理锁(即,在锁超出作用域时将其释放)?


Does std::lock call the lock() method of std::unique_lock?

Std::lock调用std::Unique_lock的lock()方法吗?


What is the advantage of using std::unique_lock with std::lock over directly passing std::mutex objects to std::lock?

将std::only_lock与std::lock一起使用直接将std::mutex对象传递给std::lock有什么好处?


struct bank_account
{
bank_account(int balance) :
mtx(), balance{ balance }

{}
std::mutex mtx;
int balance;
};

void transfer(bank_account& from, bank_account& to, int amount)
{
std::unique_lock<std::mutex> from_Lock(from.mtx, std::defer_lock);
std::unique_lock<std::mutex> to_Lock(to.mtx, std::defer_lock);
std::lock(from_Lock, to_Lock);

if (amount <= from.balance)
{
std::cout << "Before: " << amount << " from: " << from.balance << " to: " << to.balance << '\n';
from.balance -= amount;
to.balance += amount;
std::cout << "After: " << amount << " from: " << from.balance << " to: " << to.balance << '\n';
}
else
{
std::cout << amount << " is greater than " << from.balance << '\n';
}
}

int main()
{
bank_account A(200);
bank_account B(100);
std::vector<std::jthread> workers;
workers.reserve(20);
for (int i = 0; i < 10; ++i)
{
workers.emplace_back(transfer, std::ref(A), std::ref(B), 20);
workers.emplace_back(transfer, std::ref(B), std::ref(A), 10);
}
}

更多回答

Have you read cppreference's docs on std::unique_lock and std::lock() yet?

你读过关于std::only_lock和std::lock()的文档吗?

I did read but that's what exactly I wanted to know in the answer below which I couldn't find it in the resource: "when objects of std::unique_lock are passed to std::lock, the std::lock function calls the lock() method of each std::unique_lock object. This, in turn, locks the associated mutex. In this scenario, due to std::defer_lock, the mutex isn't locked directly upon the creation of the std::unique_lock object. Instead, it's locked via the std::lock function."

我读了,但这正是我在下面的答案中想知道的,但我在资源中找不到它:“当std::Unique_lock的对象传递给std::Lock时,std::lock函数调用每个std::Unique_Lock对象的lock()方法。这反过来会锁定相关的互斥锁。在这种情况下,由于std::Defer_lock,互斥锁不会在创建std::Unique_lock对象时直接锁定。相反,它是通过std::lock函数锁定的。”

优秀答案推荐

The purpose of std::lock is to provide a deadlock free locking (see libc++ implementation) of multiple Lockable objects.
The classic problem is that if you have two locks L1 and L2, and

std::lock的目的是为多个Lockable对象提供无死锁锁定(参见libc++实现)。经典的问题是,如果你有两个锁L1和L2,



  • one thread locks L1 and then L2, and

  • another thread locks L2 and then L1,


then there may be a deadlock because each thread could hold one lock and require the other from another thread. This issue applies when you're locking from.mtx and to.mtx in:

则可能会出现死锁,因为每个线程可能持有一个锁,并从另一个线程请求另一个锁。当您在以下位置从.mtx和to.mtx锁定时会出现此问题:



std::unique_lock<std::mutex> from_Lock(from.mtx, std::defer_lock);
std::unique_lock<std::mutex> to_Lock(to.mtx, std::defer_lock);
std::lock(from_Lock, to_Lock);


std::lock does the deadlock-free locking of from_Lock and to_Lock, and std::unique_lock does the rest (i.e. RAII stuff).

Std::Lock执行From_Lock和To_Lock的无死锁锁定,而std::Unique_Lock执行其余部分(即RAII内容)。


Q&A



How does std::lock work with std::unique_lock objects?

Does std::lock call the lock() method of std::unique_lock?



std::unique_lock is Lockable, and std::lock will call lock() on it, which then lock()s the mutex.

Std::only_lock是可锁的,std::lock将对其调用lock(),然后锁定()S互斥锁。



Is std::lock responsible for actually locking the from and to mutexes, while the std::unique_lock objects merely manage the locks (i.e., release them when they go out of scope)?



std::unique_lock is perfectly capable of doing locking and unlocking a mutex on its own. The only thing it can't do is implement a deadlock free locking when multiple locks are involved.

UNIQUE_LOCK完全能够单独锁定和解锁互斥锁。它唯一不能做的就是在涉及多个锁的情况下实现无死锁锁定。



What is the advantage of using std::unique_lock with std::lock over directly passing std::mutex objects to std::lock?



You would have to manually unlock both mutexes afterwards, and this is bug-prone. It's a similar problem as std::unique_ptr vs. new/delete. It would be fine if you immediately wrapped both mutexes in a std::lock_guard though.

之后,您必须手动解锁这两个互斥锁,这很容易出错。这是一个与std::only_ptr与new/Delete类似的问题。不过,如果您立即将两个互斥锁都包装在std::lock_Guard中,就可以了。


Further Improvements


For use with std::lock, you could use a simpler lock than std::unique_lock:

要与std::lock一起使用,您可以使用比std::Unique_lock:


std::lock(from.mtx, to.mtx);
std::lock_guard<std::mutex> from_lock(from.mtx, std::adopt_lock);
std::lock_guard<std::mutex> to_lock(to.mtx, std::adopt_lock);

You only need std::unique_lock if you want to transfer ownership; otherwise you can use std::lock_guard (which is a slightly simpler type).

如果您想转移所有权,则只需要std::only_lock;否则可以使用std::lock_Guard(这是一种稍微简单一些的类型)。


If you're using C++17, things get even simpler with std::scoped_lock:

如果您使用的是C++17,那么使用std::scope ed_lock会让事情变得更简单:


// CTAD, equivalent to std::scoped_lock<std::mutex, std::mutex> lock(...)
std::scoped_lock lock(from.mtx, to.mtx);

std::scoped_lock is a replacement for std::lock_guard and has deadlock free locking built into the constructor, similar to using std::lock.

STD::Scope_Lock是STD::Lock_Guard的替代,它在构造函数中内置了无死锁锁定,类似于使用STD::Lock。




See also What's the best way to lock multiple std::mutex'es?

另请参阅锁定多个std::mutex的最佳方式是什么?


更多回答

Thank you so much for detailed and very helpful explanations. Based on what you explained, I've come to understand that when objects of std::unique_lock are passed to std::lock, the std::lock function calls the lock() method of each std::unique_lock object. This, in turn, locks the associated mutex. In this scenario, due to std::defer_lock, the mutex isn't locked directly upon the creation of the std::unique_lock object. Instead, it's locked via the std::lock function which is designed to handle deadlock-free scenarios. Is my understanding accurate?

非常感谢您的详细和非常有帮助的解释。根据您所解释的内容,我已经理解了当std::Unique_lock的对象被传递给std::lock时,std::lock函数调用每个std::Unique_lock对象的lock()方法。这进而锁定了相关的互斥锁。在此场景中,由于std::defer_lock,互斥锁不会在创建std::only_lock对象时直接锁定。相反,它是通过std::lock函数锁定的,该函数旨在处理无死锁的情况。我的理解准确吗?

@Sami yes, that sounds right.Keep in mind that std::lock will call a mixture of lock(), and try_lock() until it succeeds in locking all locks.

@Sami是的,听起来是对的。请记住,std::lock将调用lock()和try_lock()的混合,直到它成功锁定所有锁。

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com