手动解锁RAII包装器的关联互斥体(如st::unique_lock)总是UB吗

Is manually unlocking associated mutex of a RAII wrapper (like st::unique_lock) always a UB?

本文关键字:unique st lock UB 总是 包装 RAII 解锁 关联      更新时间:2024-09-28

我想知道手动解锁与RAII包装器关联的互斥是否总是UB。例如,如果我们在RAII包装器像这样破坏之前再次锁定它,是否可以

int i = 0;
std::mutex mx_;
void foo() {
for (int k = 0; k < 10000; k++) {
std::unique_lock<std::mutex> lk(mx_);
i++;
mx_.unlock();
mx_.lock();
i++;
}
}

我提出这个问题的原因是,我正试图编写一个小型RAII包装器,将std::shared_mutex的共享锁升级为独占锁,我需要手动锁定/解锁与其他锁关联的std::shared_mutex,我想知道它是否是UB。这是我的upgrade_lock类:

template<typename Mutex>
class upgrade_lock {
public:
using mutex_type = Mutex;
explicit upgrade_lock(mutex_type& mx) : mxp_(&mx) {
mxp_->unlock_shared();
mxp_->lock();
}
~upgrade_lock() {
mxp_->unlock();
mxp_->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
mutex_type* mxp_ = nullptr;
};

我假设这个类只在线程获取共享锁时使用。关于为什么解锁/锁定对不由另一个互斥体保护,我认为这真的没有必要。我现在可以这样使用这个类:

int i = 0;
std::shared_mutex mx_;
void goo() {
for (int k = 0; k < 10000; k++) {
std::shared_lock<std::shared_mutex> lk(mx_);
if (i > 5000) {
upgrade_lock<std::shared_mutex> lk2(mx_);
i++;
}
}
}

如果配对正确,我不认为它是UB(@DanielLangr说,这将试图解锁一个已经解锁的互斥对象(


不过您可以直接传递锁。

template<typename lock_type>
class upgrade_lock {
public:
upgrade_lock(lock_type& src_lock):lock(&src_lock){
lock->unlock_shared();
lock->mutex()->lock();
}
~upgrade_lock() {
lock->mutex()->unlock();
lock->lock_shared();
}
upgrade_lock(const upgrade_lock&) = delete;
upgrade_lock& operator=(const upgrade_lock&) = delete;
private:
lock_type* lock;
};

(代码未测试(