锁的使用的建议和小技巧
C++使用锁的陷阱
大部分人在使用锁时都是(上锁—>处理->解锁)正常逻辑没有任何问题。但是在特殊情况容易导致无法走到解锁的那一步逻辑跳过了,这个该资源就永远被关进小黑屋了。
(标准库管理方式)使用建议,用个类来管理,或者用c++特殊的资源来作为管理
C++标准库提供了几种基本的锁类型,包括:
std::lock_guard(C++11): 简单的RAII锁管理,用于自动上锁和解锁。
std::unique_lock(C++11): 比lock_guard更灵活的锁管理,支持延迟锁定、尝试锁定、条件变量等。
std::shared_lock(C++14): 用于管理共享互斥量,允许多个线程共享读取权限。
std::scoped_lock(C++17): 可以同时锁定多个互斥量,避免死锁。
std::lock_guard 是最简单的锁类型,它在构造时自动上锁,并在析构时自动解锁。例如
std::mutex mut;
{
std::lock_guard<std::mutex> lockGuard(mut);
// 受保护的代码
}
std::unique_lock提供了更多的控制,包括手动上锁和解锁、尝试上锁、延迟上锁等。它还可以与条件变量一起使用。例如:
std::mutex mut;
{
std::unique_lock<std::mutex> uniLock(mut, std::defer_lock);
// 延迟上锁
uniLock.lock();
// 受保护的代码
uniLock.unlock();
// 可以在需要时再次上锁
}
std::shared_lock适用于读写锁(shared_mutex),允许多个线程以共享模式读取,但写入时需要独占。例如
std::shared_mutex sharedMut;
{
std::shared_lock<std::shared_mutex> sharedLock(sharedMut);
// 多个线程可以共享读取
}
std::scoped_lock可以同时管理多个互斥量,使用避免死锁的算法来上锁。例如:
std::mutex mut1, mut2;
{
std::scoped_lock lock(mut1, mut2);
// 同时管理多个互斥量
}
下面自己实现一个管理的源码,创建一个简单的类管理模块,共学习和使用
类似于lock_guard的简单用法,采用了类的构造上锁,析构所资源释放,或许这就是对象带来的好处把0_0.
std::mutex mut;
{
au max(mut);
//操作资源(锁定中)
}
//到此资源主动释放
源码实现如下个人实现了多种锁的使用,同时支持类模板的实现
/*
使用poco库中的mutex
方法 AutoMutex am(poco:: mutex);主动锁,走出作用域的时候主动释放不需要解锁
*/
#define USING_POCO_BL
/*
使用类模板自动识别锁的类型
方法 AutoMutex am(poco:: mutex);主动锁,走出作用域的时候主动释放不需要解锁
*/
//#define USING_TEMPLATE_BL
#ifdef USING_POCO_BL
template <class T = void>
#endif
class AutoMutex //只做位poco的锁来使用
{
private:
#ifdef USING_POCO_BL
Poco::Mutex* poco_mutex;
#endif
std::mutex* std_mutex;
#ifdef USING_TEMPLATE_BL
T *auto_mute;
#endif
uint8_t type;
/* data */
public:
#ifdef USING_POCO_BL
AutoMutex(Poco::Mutex *mute):
type(0),
poco_mutex(mute),
std_mutex(nullptr)
{poco_mutex->lock();};
AutoMutex(Poco::Mutex *mute, long milliseconds):
type(0),
poco_mutex(mute),
std_mutex(nullptr)
{poco_mutex->lock(milliseconds);};
#endif
AutoMutex(std::mutex *mute):
type(1),
poco_mutex(nullptr),
std_mutex(mute)
{poco_mutex->lock();};
#ifdef USING_TEMPLATE_BL
template<class T>
AutoMutex(T *mute):type(200):auto_mute(mute){
auto_mute.lock();
};
#endif
~AutoMutex(){
#ifdef USING_POCO_BL
if(type == 0){
if(poco_mutex != nullptr)poco_mutex->unlock();
}
else
#endif
if(type == 1){
if(std_mutex != nullptr)std_mutex->unlock();
}
else
if(type == 200){
#ifdef USING_TEMPLATE_BL
if(auto_mute != nullptr)auto_mute->unlock();
#endif
}
};
};