为什么 std::lock() 在使用我自己的 unique_lock 对象时会导致无限循环?
Why std::lock() causes the endless loop when works with my own unique_lock object?
我正在尝试实现 unique_lock 的模拟(这只是研究任务,我知道标准库实现完美无缺)。
我已经编写了我需要的所有方法,现在我正在尝试根据 https://en.cppreference.com/w/cpp/thread/unique_lock/unique_lock 中的示例测试我的代码。
说到std::lock(lk_b,lk_c);无限循环开始。
我做了一些 cout 以了解程序在哪里失去控制,结果如下:锁定 -> 尝试 -> 解锁 -> 锁定 -> 尝试 -> 解锁。
这里是部分 unique_lock 实现(我只包含了示例问题部分使用的那些方法)。
template<typename Mutex>
class my_unique_lock {
Mutex *lockable;
bool is_acquired;
public:
explicit my_unique_lock(Mutex& m): lockable{&m}, is_acquired{true}{
lockable->lock();
//std::cout << "constructor my_unique_lock(Mutex& m)" << std::endl;
}
my_unique_lock(Mutex& m, std::defer_lock_t t): lockable{&m}, is_acquired{false}{
std::cout << "constructor my_unique_lock(Mutex& m, std::defer_lock_t t)" << std::endl;
}
bool try_lock(){
std::cout << "try_lock" << std::endl;
if(lockable == nullptr)
throw std::system_error();
is_acquired = mutex()->try_lock();
return is_acquired;
}
void lock(){
std::cout << "lock" << std::endl;
if(lockable == nullptr || owns_lock())
throw std::system_error();
mutex()->lock();
is_acquired = true;
}
void unlock(){
//std::cout << "unlock" << std::endl;
if(lockable == nullptr || !owns_lock())
throw std::system_error();
mutex()->unlock();
is_acquired = false;
std::cout << "unlocked" << std::endl;
}
Mutex *mutex() const noexcept {
//std::cout << "*mutex()" << std::endl;
return lockable;
}
bool owns_lock() const noexcept {
//std::cout << "owns_lock()" << std::endl;
return lockable != nullptr && is_acquired;
}
~my_unique_lock(){
//std::cout << "destructor" << std::endl;
if(mutex() != nullptr && owns_lock()){
mutex()->unlock();
is_acquired = false;
}
}
};
这是示例。
void update(std::mutex &m_a, std::mutex &m_b, std::mutex &m_c, int &a, int &b, int &c)
{
{
my_unique_lock<std::mutex> lk(m_a);
a++;
}
{
my_unique_lock<std::mutex> lk_b(m_b, std::defer_lock);
my_unique_lock<std::mutex> lk_c(m_c, std::defer_lock);
std::lock(lk_b, lk_c);
b = std::exchange(c, b + c);
}
}
int main()
{
std::mutex m_a, m_b, m_c;
int a, b, c = 1;
std::vector<std::thread> threads;
for (unsigned i = 0; i < 1; ++i)
threads.emplace_back(update, std::ref(m_a), std::ref(m_b), std::ref(m_b), std::ref(a), std::ref(b), std::ref(c));
for (auto& i: threads)
i.join();
std::cout << a << "'th and " << a+1 << "'th Fibonacci numbers: "
<< b << " and " << c << '\n';
}
所以,正如我所说,我真的不明白为什么 lock() 会导致这样的调用链(锁定 -> try_lock -> 解锁)的无限循环。
将 std::ref(m_b), std::ref(m_b)
更改为 std::ref(m_b), std::ref(m_c)
。 Copy/paste 打字错误。
您的 std::lock
正在尝试锁定 m_b
两次。
其他问题:您违反了 0/3/5 的规则。您有多个不同的 near-identical 锁摆弄 lock/unlock 代码(重构)。
我正在尝试实现 unique_lock 的模拟(这只是研究任务,我知道标准库实现完美无缺)。
我已经编写了我需要的所有方法,现在我正在尝试根据 https://en.cppreference.com/w/cpp/thread/unique_lock/unique_lock 中的示例测试我的代码。
说到std::lock(lk_b,lk_c);无限循环开始。
我做了一些 cout 以了解程序在哪里失去控制,结果如下:锁定 -> 尝试 -> 解锁 -> 锁定 -> 尝试 -> 解锁。
这里是部分 unique_lock 实现(我只包含了示例问题部分使用的那些方法)。
template<typename Mutex>
class my_unique_lock {
Mutex *lockable;
bool is_acquired;
public:
explicit my_unique_lock(Mutex& m): lockable{&m}, is_acquired{true}{
lockable->lock();
//std::cout << "constructor my_unique_lock(Mutex& m)" << std::endl;
}
my_unique_lock(Mutex& m, std::defer_lock_t t): lockable{&m}, is_acquired{false}{
std::cout << "constructor my_unique_lock(Mutex& m, std::defer_lock_t t)" << std::endl;
}
bool try_lock(){
std::cout << "try_lock" << std::endl;
if(lockable == nullptr)
throw std::system_error();
is_acquired = mutex()->try_lock();
return is_acquired;
}
void lock(){
std::cout << "lock" << std::endl;
if(lockable == nullptr || owns_lock())
throw std::system_error();
mutex()->lock();
is_acquired = true;
}
void unlock(){
//std::cout << "unlock" << std::endl;
if(lockable == nullptr || !owns_lock())
throw std::system_error();
mutex()->unlock();
is_acquired = false;
std::cout << "unlocked" << std::endl;
}
Mutex *mutex() const noexcept {
//std::cout << "*mutex()" << std::endl;
return lockable;
}
bool owns_lock() const noexcept {
//std::cout << "owns_lock()" << std::endl;
return lockable != nullptr && is_acquired;
}
~my_unique_lock(){
//std::cout << "destructor" << std::endl;
if(mutex() != nullptr && owns_lock()){
mutex()->unlock();
is_acquired = false;
}
}
};
这是示例。
void update(std::mutex &m_a, std::mutex &m_b, std::mutex &m_c, int &a, int &b, int &c)
{
{
my_unique_lock<std::mutex> lk(m_a);
a++;
}
{
my_unique_lock<std::mutex> lk_b(m_b, std::defer_lock);
my_unique_lock<std::mutex> lk_c(m_c, std::defer_lock);
std::lock(lk_b, lk_c);
b = std::exchange(c, b + c);
}
}
int main()
{
std::mutex m_a, m_b, m_c;
int a, b, c = 1;
std::vector<std::thread> threads;
for (unsigned i = 0; i < 1; ++i)
threads.emplace_back(update, std::ref(m_a), std::ref(m_b), std::ref(m_b), std::ref(a), std::ref(b), std::ref(c));
for (auto& i: threads)
i.join();
std::cout << a << "'th and " << a+1 << "'th Fibonacci numbers: "
<< b << " and " << c << '\n';
}
所以,正如我所说,我真的不明白为什么 lock() 会导致这样的调用链(锁定 -> try_lock -> 解锁)的无限循环。
将 std::ref(m_b), std::ref(m_b)
更改为 std::ref(m_b), std::ref(m_c)
。 Copy/paste 打字错误。
您的 std::lock
正在尝试锁定 m_b
两次。
其他问题:您违反了 0/3/5 的规则。您有多个不同的 near-identical 锁摆弄 lock/unlock 代码(重构)。