前言
在近日学习中发现,如果开发一个单例模式的日志系统,难免会出现多个线程记录日志的情况,这个时候线程可能导致竞争,或者始料未及的情况发生。
通过学习,如果要保证线程安全,要使用互斥锁QMutex,和QMutexLocker。
根据官方文档对这两个类进行解释:
QMutex:保证一个对象、数据结构或者代码片段在同一时间只有一个线程可以访问。经常和QMutexLocker一起使用,达到自动释放锁的效果。
QMutexLocker:是一个用来简化QMutex加锁和解锁的类。
看了具体解释,现在我来具体使用,假设我有一个Logger.h文件,在下面添加一个QMutex mutex_;
class Logger : public QObject
{
Q_OBJECT
public:
void log(LogLevel level, const QString& message); // 假设要这个函数线程安全
// ...其他定义
private:
// 添加这个成员变量。
QMutex mutex_;
};
然后在写入日志的函数开始就加上这么一行,就让写入操作是线程安全的了。如同注释,离开这个作用域,锁会被自动打开。
void Logger::log(LogLevel level, const QString& message)
{
// 离开这个作用域时自动解锁
QMutexLocker locker(&mutex_);
//... 写入日志的操作
}
如果不使用QMutexLocker,那么要这样手动加锁和解锁。
void Logger::log(LogLevel level, const QString& message)
{
// 加锁
mutex_.lock();
//... 写入日志的操作
// 解锁
mutex_.unlock();
}
如下,大家仔细思考就会发现,万一在写入日志过程中使用了return,函数提前结束,是不是就会出现没有解锁的情况,这肯定是不安全的。所以还是建议QMutex和QMutexLocker一起使用。
void Logger::log(LogLevel level, const QString& message)
{
// 加锁
mutex_.lock();
//... 写入日志的操作
// 假设这里不小心return了,导致没有解锁,出现不安全的情况
return;
// 解锁
mutex_.unlock();
}