【Qt】如何保证线程安全(以日志写入为例)

发布于:2025-02-11 ⋅ 阅读:(137) ⋅ 点赞:(0)

前言

在近日学习中发现,如果开发一个单例模式的日志系统,难免会出现多个线程记录日志的情况,这个时候线程可能导致竞争,或者始料未及的情况发生。

通过学习,如果要保证线程安全,要使用互斥锁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();
}