(Shared) mutex in C++

9 浏览
0 Comments

(Shared) mutex in C++

我看到了一个共享互斥锁的示例:\n

class MyData {
    std::vector data_;
    mutable shared_mutex mut_;   // 用于保护 data_ 的互斥锁;
public:
    void write() {
        unique_lock lk(mut_);
        // ... 写入 data_ ...
    }
    void read() const {
        shared_lock lk(mut_);
        // ... 读取数据 ...
    }
};

\n自然而然,我会这样编写:\n

public:
    void write() {
        mut_.lock();
        // ... 写入 data_ ...
        mut_.unlock();
    }
    void read() const {
        mut_.lock_shared();
        // ... 读取数据 ...
        mut_.unlock_shared();
    }
};

\n我的方式正确吗?我使用的方式和示例中使用的方式有什么区别吗?另外,它们之间有什么优势呢?谢谢!

0
0 Comments

((Shared) mutex in C++)这个问题的出现的原因是因为原始的互斥锁(raw mutex)在某些情况下存在安全问题,因此一般会使用RAII版本的互斥锁unique_lock()来取代原始的互斥锁。

解决方法是使用unique_lock()来替代原始的互斥锁。unique_lock()是一种RAII(Resource Acquisition Is Initialization,资源获取即初始化)的机制,它能够保证在两种情况下的安全性:异常和提前返回。

与原始指针一样,原始的互斥锁也一般会被避免使用,而选择使用RAII版本的智能指针(smart pointers):unique_ptr或shared_ptr。

不论是哪种情况,RAII版本都能够确保在作用域结束时互斥锁(或指针)总是被释放。

下面是示例代码:

#include 
std::mutex mtx; // 原始的互斥锁
void foo()
{
    std::unique_lock lock(mtx); // 使用unique_lock代替原始的互斥锁
    // 执行一些操作
}

使用unique_lock()能够更好地处理异常和提前返回的情况,确保互斥锁的安全性。这种RAII的机制能够避免手动释放资源的繁琐操作,提高代码的可读性和可维护性。因此,在C++中使用((Shared) mutex)时,我们一般会选择使用unique_lock()来替代原始的互斥锁。

0
0 Comments

在C++中使用((Shared) mutex)时出现的问题是,如果在锁定互斥量和解锁之间的代码抛出异常,互斥量将保持锁定状态。这可能导致资源泄漏或死锁的情况。

解决方法是使用std::unique_lock替代std::lock_guard来管理互斥量的锁定和解锁。std::unique_lock遵循RAII习惯用法,即在异常情况下会自动处理互斥量的解锁。当std::unique_lock对象的析构函数被调用时,它会解锁关联的互斥量(如果互斥量被锁定)。

下面是使用std::unique_lock的示例代码:

void write() {
    std::unique_lock lk(mut_);
    // <-- 在这里抛出异常
}

在这个例子中,如果在创建std::unique_lock对象之后抛出异常,它的析构函数会被调用,并且会解锁关联的互斥量。

总之,使用std::unique_lock//std::shared_lock,不需要在异常情况下或者从不同的执行路径离开成员函数时进行特殊处理。

另外需要注意的是,从C++17开始,建议使用std::scoped_lock而不是std::lock_guard。尽管std::scoped_lock比std::lock_guard更灵活,但在这种情况下,您似乎不需要那种灵活性。而std::unique_lock则更适合您的需求,因为它实现了unlock(),而std::scoped_lock则没有这个功能。

0