我想知道手动解锁与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;
};
(代码未测试(