参考
主要参考B站up主恋恋风辰:恋恋风辰官方博客
测试加锁
cpp
#include <iostream>
#include <mutex>
#include <map>
#include <stack>
#include <shared_mutex>
// 基本的加锁使用
std::mutex mtx1;
void use_lock()
{
int count = 10;
while (count--)
{
#if 0
mtx1.lock();
shared_data++;
std::cout << "current thread is " << std::this_thread::get_id() << std::endl;
std::cout << "sharad data is " << shared_data << std::endl;
mtx1.unlock();
#endif
// 直接使用lock_guard加锁, 程序结束自动释放
std::lock_guard<std::mutex> lock(mtx1);
shared_data++;
std::cout << "current thread is " << std::this_thread::get_id() << std::endl;
std::cout << "sharad data is " << shared_data << std::endl;
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
}
void test_lock()
{
std::thread t1(use_lock);
std::thread t2([]() {
int count = 10;
while (count--) {
mtx1.lock();
shared_data--;
std::cout << "current thread is " << std::this_thread::get_id() << std::endl;
std::cout << "sharad data is " << shared_data << std::endl;
mtx1.unlock();
std::this_thread::sleep_for(std::chrono::microseconds(10));
}
});
t1.join();
t2.join();
}
int main()
{
// 1. 测试加锁
test_lock();
std::cout << "Finished! \n";
}
测试线程安全数据结构1
cpp
// 保证数据安全
// 1. 错误实现
template<typename T>
class threadsafe_stack1
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
threadsafe_stack1() {}
threadsafe_stack1(const threadsafe_stack1& other)
{
std::lock_guard<std::mutex> lock(other.m);
//①在构造函数的函数体(constructor body)内进行复制操作
data = other.data;
}
threadsafe_stack1& operator=(const threadsafe_stack1&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value));
}
//问题代码
T pop()
{
std::lock_guard<std::mutex> lock(m);
auto element = data.top();
data.pop();
return element;
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
void test_threadsafe_stack1() {
threadsafe_stack1<int> safe_stack;
safe_stack.push(1);
// 两个线程同时抛出,可能存在隐患,相当于pop了两次
std::thread t1([&safe_stack]() {
if (!safe_stack.empty()) {
std::this_thread::sleep_for(std::chrono::seconds(2));
safe_stack.pop();
}
});
std::thread t2([&safe_stack]() {
if (!safe_stack.empty()) {
std::this_thread::sleep_for(std::chrono::seconds(2));
safe_stack.pop();
}
});
t1.join();
t2.join();
}
// 重新实现的线程安全栈
struct empty_stack : std::exception
{
const char* what() const throw();
};
template<typename T>
class threadsafe_stack
{
private:
std::stack<T> data;
mutable std::mutex m;
public:
threadsafe_stack() {}
threadsafe_stack(const threadsafe_stack& other)
{
std::lock_guard<std::mutex> lock(other.m);
//①在构造函数的函数体(constructor body)内进行复制操作
data = other.data;
}
threadsafe_stack& operator=(const threadsafe_stack&) = delete;
void push(T new_value)
{
std::lock_guard<std::mutex> lock(m);
data.push(std::move(new_value));
}
std::shared_ptr<T> pop()
{
std::lock_guard<std::mutex> lock(m);
// 试图弹出前检查是否为空栈
if (data.empty()) throw empty_stack();
// 改动栈容器前设置返回值
// 操作智能指针效率更高一些
std::shared_ptr<T> const res(std::make_shared<T>(data.top()));
data.pop();
return res;
}
void pop(T& value)
{
std::lock_guard<std::mutex> lock(m);
if (data.empty()) throw empty_stack();
value = data.top();
data.pop();
}
bool empty() const
{
std::lock_guard<std::mutex> lock(m);
return data.empty();
}
};
int main()
{
// 2. 测试线程线程安全
// test_threadsafe_stack1();
std::cout << "Finished! \n";
}
死锁以及解决方案
cpp
// 关于死锁
// 加锁的顺序不对,互相占有对方的锁
// 解决方案1: 将加锁,解锁封装为独立的函数, 这样一个函数内不会使用多个锁
std::mutex t_lock1;
std::mutex t_lock2;
int m_1, m_2;
void atomic_lock1()
{
std::cout << "Lock1 begin lock" << std::endl;
t_lock1.lock();
m_1 = 1024;
t_lock1.unlock();
std::cout << "Lock1 end lock" << std::endl;
}
void atomic_lock2()
{
std::cout << "Lock2 begin lock" << std::endl;
t_lock2.lock();
m_2 = 2048;
t_lock2.unlock();
std::cout << "Lock2 end lock" << std::endl;
}
void safe_lock1()
{
int count = 10;
while (count--) {
atomic_lock1();
atomic_lock2();
std::this_thread::sleep_for(std::chrono::microseconds(5));
}
}
void safe_lock2()
{
int count = 10;
while (count--) {
atomic_lock1();
atomic_lock2();
std::this_thread::sleep_for(std::chrono::microseconds(5));
}
}
void test_safe_lock()
{
std::thread t1(safe_lock1);
std::thread t2(safe_lock2);
t1.join();
t2.join();
}
int main()
{
// 3. 死锁
// 解决方案1
test_safe_lock();
std::cout << "Finished! \n";
}
测试交换两个特别大的对象
cpp
// 同时加锁
class some_big_obj
{
public:
some_big_obj(int data): _data(data){}
// 拷贝构造
some_big_obj(const some_big_obj& b) : _data(b._data)
{
_data = b._data;
}
// 移动构造
some_big_obj(some_big_obj&& b): _data(std::move(b._data)){}
// 重载运算符
friend std::ostream& operator << (std::ostream& os, const some_big_obj& big_obj)
{
os << big_obj._data;
return os;
}
// 重载赋值运算符
some_big_obj& operator = (const some_big_obj& b)
{
if (this == &b) return *this;
_data = b._data;
return *this;
}
// 交换数据
friend void swap(some_big_obj& b1, some_big_obj& b2)
{
some_big_obj temp = std::move(b1);
b1 = std::move(b2);
b2 = std::move(temp);
}
private:
int _data;
};
// 实现一个管理者class
class big_obj_manager
{
private:
std::mutex _mtx;
some_big_obj _obj;
public:
big_obj_manager(int data = 0): _obj(data){}
void printInfo()
{
std::cout << "Curr obj data is " << _obj << std::endl;
}
friend void danger_swap(big_obj_manager& objm1, big_obj_manager& objm2);
friend void safe_swap(big_obj_manager& objm1, big_obj_manager& objm2);
friend void safe_swap_scope(big_obj_manager& objm1, big_obj_manager& objm2);
};
// 危险的交换方式1
void danger_swap(big_obj_manager& objm1, big_obj_manager& objm2) {
std::cout << "thread [ " << std::this_thread::get_id() << " ] begin" << std::endl;
if (&objm1 == &objm2) {
return;
}
std::lock_guard <std::mutex> gurad1(objm1._mtx);
//此处为了故意制造死锁,我们让线程小睡一会
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> guard2(objm2._mtx);
swap(objm1._obj, objm2._obj);
std::cout << "thread [ " << std::this_thread::get_id() << " ] end" << std::endl;
}
void test_danger_swap()
{
big_obj_manager objm1(5);
big_obj_manager objm2(100);
std::thread t1(danger_swap, std::ref(objm1), std::ref(objm2));
std::thread t2(danger_swap, std::ref(objm1), std::ref(objm2));
t1.join();
t2.join();
objm1.printInfo();
objm2.printInfo();
}
// 为了避免死锁,同时对两个锁加锁
void safe_swap(big_obj_manager& objm1, big_obj_manager& objm2)
{
std::cout << "thread [ " << std::this_thread::get_id() << " ] begin" << std::endl;
if (&objm1 == &objm2) {
return;
}
// 同时对两个互斥量加锁
std::lock(objm1._mtx, objm2._mtx);
// 使用领养锁管理自动释放
std::lock_guard<std::mutex> gurad1(objm1._mtx, std::adopt_lock);
// 领养后会自动释放
std::this_thread::sleep_for(std::chrono::seconds(1));
std::lock_guard<std::mutex> gurads(objm2._mtx, std::adopt_lock);
swap(objm1._obj, objm2._obj);
std::cout << "thread [ " << std::this_thread::get_id() << " ] end" << std::endl;
}
void test_safe_swap()
{
big_obj_manager objm1(5);
big_obj_manager objm2(100);
std::thread t1(safe_swap, std::ref(objm1), std::ref(objm2));
std::thread t2(safe_swap, std::ref(objm2), std::ref(objm1));
t1.join();
t2.join();
objm1.printInfo();
objm2.printInfo();
}
int main()
{
#if 0
// 危险交换测试
test_danger_swap();
#endif
// 安全的交换方式
test_safe_swap();
std::cout << "Finished! \n";
}
层级锁避免死锁
cpp
// 实际开发中,锁的顺序可能很难注意,可以使用层级锁避免死锁
class hierarchical_mutex
{
private:
std::mutex _internal_mutex;
unsigned long const _hierarchy_value; // 当前层级值
unsigned long _previous_hierarchy_value; // 上一层级值
static thread_local unsigned long _this_thread_hierarchy_value; // 记录本线程层级值
void check_for_hierarchy_violation()
{
if (_this_thread_hierarchy_value <= _hierarchy_value)
{
throw std::logic_error("mutex hierarchy violated");
}
}
void update_hierachy_value()
{
_previous_hierarchy_value = _this_thread_hierarchy_value;
_this_thread_hierarchy_value = _hierarchy_value;
}
public:
explicit hierarchical_mutex(unsigned long value): _hierarchy_value(value), _previous_hierarchy_value(0){}
hierarchical_mutex(const hierarchical_mutex&) = delete;
hierarchical_mutex& operator=(const hierarchical_mutex&) = delete;
void lock()
{
check_for_hierarchy_violation();
_internal_mutex.lock();
update_hierachy_value();
}
void unlock()
{
if (_this_thread_hierarchy_value != _hierarchy_value)
throw std::logic_error("mutex hierachy violated");
_this_thread_hierarchy_value = _previous_hierarchy_value;
_internal_mutex.unlock();
}
bool try_lock()
{
check_for_hierarchy_violation();
if (!_internal_mutex.try_lock()) {
return false;
}
update_hierachy_value();
return false;
}
};
// 初始化静态变量
thread_local unsigned long hierarchical_mutex::_this_thread_hierarchy_value(ULONG_MAX);
// 测试层级锁
void test_hierarchy_lock()
{
hierarchical_mutex hmtx1(1000);
hierarchical_mutex hmtx2(500);
std::thread t1([&hmtx1, &hmtx2]() {
hmtx1.lock();
hmtx2.lock();
hmtx2.unlock();
hmtx1.unlock();
});
#if 0
// 以下是错误代码
std::thread t2([&hmtx1, &hmtx2]() {
hmtx2.lock();
hmtx1.lock();
hmtx1.unlock();
hmtx2.unlock();
});
#endif
t1.join();
// t2.join();
}
int main()
{
// 4. 实现一个层级锁
test_hierarchy_lock();
std::cout << "Finished! \n";
}