C++中通过实例化 std::mutex
创建互斥量, 通过调用成员函数lock()
进行上锁, unlock()
进行解锁。 不过, 不推荐实践中直接去调用成员函数, 因为调用成员函数就意味着, 必须记住在每个函数出口都要去调用unlock()
, 也包括异常的情况。
C++标准库为互斥量提供了一个RAII语法的模板类 std::lock_guard
, 其会在构造的时候提供已锁的互斥量, 并在析构的时候进行解锁, 从而保证了一个已锁的互斥量总是会被正确的解锁。
下面的程序清单中, 展示了如何在多线程程序中, 使用 std::mutex
构造的 std::lock_guard
实例, 对一个列表进行访问保护。 std::mutex
和 std::lock_guard
都在 <mutex> 头文件中声明。
#include <list>
#include <mutex>
#include <algorithm>
std::list<int> some_list; // 1
std::mutex some_mutex; // 2
void add_to_list(int new_value)
{
std::lock_guard<std::mutex> guard(some_mutex); // 3
some_list.push_back(new_value);
}
bool list_contains(int value_to_find)
{
std::lock_guard<std::mutex> guard(some_mutex); // 4
return std::find(some_list.begin(),some_list.end(),value_to_find) != some_list.end();
}
上面代码中有一个全局变量①, 这个全局变量被一个全局的互斥量保护②。 add_to_list()
③和list_contains()
④函数中使用 std::lock_guard<std::mutex>
, 使得这两个函数中对数据的访问是互斥的:
list_contains()
不可能看到正在被add_to_list()
修改的列表。
虽然某些情况下, 使用全局变量没问题, 但在大多数情况下, 互斥量通常会与保护的数据放在同一个类中, 而不是定义成全局变量。 这是面向对象设计的准则: 将其放在一个类中, 就可让他们联系在一起, 也可对类的功能进行封装, 并进行数据保护。 在这种情况下, 函数add_to_list
和list_contains
可以作为这个类的成员函数。 互斥量和要保护的数据, 在类中都需要定义为private成员, 这会让访问数据的代码变的清晰, 并且容易看出在什么时候对互斥量上锁。 当所有成员函数都会在调用时对数据上锁, 结束时对数据解锁, 那么就保证了数据访问时不变量不被破坏。
但当其中一个成员函数返回的是保护数据的指针或引用时, 会破坏对数据的保护。 具有访问能力的指针或引用可以访问(并可能修改)被保护的数据, 而不会被互斥锁限制。 互斥量保护的数据需要对接口的设计相当谨慎, 要确保互斥量能锁住任何对保护数据的访问, 并且不留后门。
标签:std,保护,some,list,互斥,guard,mutex,共享 From: https://www.cnblogs.com/love-9/p/18093188