参考
主要参考B站up主恋恋风辰:恋恋风辰官方博客
测试加锁
#include <iostream>
#include <mutex>
#include <map>
#include <stack>
#include <shared_mutex>// 基本的加锁使用
std::mutex mtx1;void use_lock()
{int count = 10;while (count--){
#if 0mtx1.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
// 保证数据安全
// 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";
}
死锁以及解决方案
// 关于死锁
// 加锁的顺序不对,互相占有对方的锁
// 解决方案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. 死锁// 解决方案1test_safe_lock();std::cout << "Finished! \n";
}
测试交换两个特别大的对象
// 同时加锁
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";
}
层级锁避免死锁
// 实际开发中,锁的顺序可能很难注意,可以使用层级锁避免死锁
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();});
#endift1.join();// t2.join();
}int main()
{// 4. 实现一个层级锁test_hierarchy_lock();std::cout << "Finished! \n";
}