Qt互斥锁【QMutex】的使用、QMutexLocker的使用
- Chapter1 Qt互斥锁(QMutex)的使用、QMutexLocker的使用
- 一、QMutexLocker和QMutex实现示例图
- 二、QMutex和QMutexLocker的关系(个人理解)
- 三、QMutex使用和QMutexLocker使用
- 1.QMutex的使用
- 2.QMutexLocker的使用
- 四、检验QMutexLocker是否将传入的互斥锁锁定
- 1.操作解释
- 2.CMoveFuncClass(使用moveToThread实现,使用QMutexLocker)
- 3.CThread类(继承QThread实现,单纯使用QMutex)
- 4.CMainWindow调用类
- 总结
- 相关文章
Chapter1 Qt互斥锁(QMutex)的使用、QMutexLocker的使用
原文链接:https://blog.csdn.net/wj584652425/article/details/123585126
一、QMutexLocker和QMutex实现示例图
下图为检测QMutexLocker是否上锁成功的示例图(两个线程使用同一个QMutex),源码在文章第四节(源码含详细注释)。
下图为不同QMutex运行时的效果(该图表明两个线程无关,并非sleep影响了另一个线程的运行)
二、QMutex和QMutexLocker的关系(个人理解)
互斥锁(QMutex)在使用时需要在进入和结束的时候使用对应的函数锁定和解锁。在简单的程序中还好,但是在结构复杂的程序中因为需要手动锁定和解锁,很容易忽略细节而出现问题,于是为了应对这种情况QMutexLocker便诞生了(为了简化简化互斥锁的锁定和解锁)。
QMutexLocker通常创建为局部变量,QMutexLocker在创建时传入一个并未锁定(若是锁定可用relock重新锁定或unlock解锁)的QMutex指针变量,并且会将QMutex变量锁定,在释放时会将QMutex变量解锁。(QMutexLocker创建时将传入的QMutex锁定,释放时将传入的QMutex解锁)
三、QMutex使用和QMutexLocker使用
1.QMutex的使用
void CThread::run()
{
//互斥锁锁定
m_mutex->lock();
//输出当前线程的线程ID
qDebug() << QThread::currentThreadId();
//互斥锁解锁
m_mutex->unlock();
}
2.QMutexLocker的使用
void CThread::run()
{
//创建QMutexLocker的局部变量,并将类中互斥锁指针传入(此处互斥锁被locker锁定)
QMutexLocker locker(m_mutex);
qDebug() << QThread::currentThreadId();
//当locker作用域结束locker将互斥锁解锁
}
通过1、2的代码比较,我们会发现QMutexLocker的代码中没有手动调用锁定和解锁,由此可看出MutexLocker简化了互斥锁的锁定和解锁。
四、检验QMutexLocker是否将传入的互斥锁锁定
1.操作解释
使用两种实现方法完全不同线程测试
两个线程使用同一个互斥锁
一个线程使用QMutexLocker一个线程单纯使用QMutex
2.CMoveFuncClass(使用moveToThread实现,使用QMutexLocker)
CMoveFuncClass.h
#ifndef CMOVEFUNCCLASS_H
#define CMOVEFUNCCLASS_H
#include <QObject>
#include <QMutex>
class CMoveFuncClass : public QObject
{
Q_OBJECT
public:
explicit CMoveFuncClass(QObject *parent = nullptr);
~CMoveFuncClass();
void setMutex(QMutex *mutex);
public slots:
void doSomething();
private:
QMutex * m_mutex; //定义一个互斥锁变量
};
#endif // CMOVEFUNCCLASS_H
CMoveFuncClass.cpp
#include "CMoveFuncClass.h"
#include <QDebug>
#include <QThread>
CMoveFuncClass::CMoveFuncClass(QObject *parent)
: QObject(parent)
{
}
CMoveFuncClass::~CMoveFuncClass()
{
}
void CMoveFuncClass::doSomething()
{
//创建QMutexLocker的局部变量,并将类中互斥锁指针传入(此处互斥锁被locker锁定)
QMutexLocker locker(m_mutex);
qDebug() << "我的实现方法为moveToThread" <<"开始3秒睡眠" << "使用QMutexLocker";
qDebug() << "线程ID:" << QThread::currentThreadId();
QThread::sleep(3); //设置线程睡眠3秒(单位为秒)
qDebug() << "我的实现方法为moveToThread" <<"线程运行完成,结束睡眠\n\n";
//当locker作用域结束locker将互斥锁解锁
}
void CMoveFuncClass::setMutex(QMutex *mutex)
{
m_mutex = mutex;
}
3.CThread类(继承QThread实现,单纯使用QMutex)
CThread.h
#ifndef CTHREAD_H
#define CTHREAD_H
#include <QObject>
#include <QThread>
#include <QMutex>
#include <QWaitCondition>
class CThread : public QThread
{
Q_OBJECT
public:
explicit CThread(QObject *parent = nullptr);
~CThread();
void run();
void setMutex(QMutex *mutex);
private:
QMutex * m_mutex; //定义一个线程锁变量
};
#endif // CTHREAD_H
CThread.cpp
#include "CThread.h"
#include <QDebug>
CThread::CThread(QObject *parent)
: QThread(parent)
{
}
CThread::~CThread()
{
}
void CThread::run()
{
//互斥锁上锁
m_mutex->lock();
qDebug() << "我的实现方法为继承QThread" << "开始3秒睡眠" << "单纯使用QMutex";
qDebug() << "线程ID:" << QThread::currentThreadId();
QThread::sleep(3); //设置线程睡眠3秒(单位为秒)
qDebug() << "我的实现方法为继承QThread" <<"线程运行完成,结束睡眠";
//互斥锁解锁
m_mutex->unlock();
}
void CThread::setMutex(QMutex *mutex)
{
m_mutex = mutex;
}
4.CMainWindow调用类
CMainWindow.h
#ifndef CMAINWINDOW_H
#define CMAINWINDOW_H
#include <QMainWindow>
#include "CThread.h"
#include "CMoveFuncClass.h"
namespace Ui {
class CMainWindow;
}
class CMainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit CMainWindow(QWidget *parent = 0);
~CMainWindow();
signals:
void startMoveThread();
private slots:
void on_startBtn_clicked(); //触发方法二函数的信号
private:
Ui::CMainWindow *ui;
CThread *m_cThread; //方法一指针
CMoveFuncClass *m_moveFunc; //方法二指针
QThread *m_thread; //方法二所移至的线程指针
QMutex *m_mutex; //两个线程使用的线程锁
};
#endif // CMAINWINDOW_H
CMainWindow.cpp
#include "CMainWindow.h"
#include "ui_CMainWindow.h"
#include <QDebug>
CMainWindow::CMainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::CMainWindow)
{
ui->setupUi(this);
/方法一///
//new出CThread对象
m_cThread = new CThread;
/方法二///
//new一个moveToThread的接收线程并启动
m_thread = new QThread;
//new出CMoveFuncClass对象
m_thread->start(); //一定记得启动,否则运行不了
m_moveFunc = new CMoveFuncClass;
//连接相应信号槽
connect(this, &CMainWindow::startMoveThread, m_moveFunc, &CMoveFuncClass::doSomething);
connect(m_thread, &QThread::finished, m_moveFunc, &QObject::deleteLater);
//将对象移至线程
m_moveFunc->moveToThread(m_thread);
//创建线程共用的互斥锁
m_mutex = new QMutex;
//下方为m_mutex的地方更改为new QMutex,则能实现第一节,第二张图的效果
m_cThread->setMutex(m_mutex);
m_moveFunc->setMutex(m_mutex);
}
CMainWindow::~CMainWindow()
{
delete m_mutex;
delete m_moveFunc;
m_thread->exit();
m_thread->wait(1);
delete m_thread;
m_cThread->exit();
m_cThread->wait(1);
delete m_cThread;
delete ui;
}
void CMainWindow::on_startBtn_clicked()
{
//通过start启动方法一线程
m_cThread->start();
//发送信号启动方法二线程
emit startMoveThread();
}
运行上方的代码(第一节,第一张效果图)可看出,使用QMutexLocker的线程首先运行,且代码中无锁定和解锁的操作,但另外一个线程依然等该线程运行完成后运行,由此可看出,使用QMutexLocker是实现了互斥锁的锁定和解锁的。
总结
QMutexLocker提供的简化互斥锁锁定和解锁的机制在很多时候时蛮方便的,在使用互斥锁的地方使用QMutexLocker会减去许多安全隐患;不过在多线程循环输出ABC的时候好像就不适合该方法。所以使用类似的类还得按情况而定
相关文章
启动QThread线程的两种方法(含源码+注释)
Qt互斥锁(QMutex)、条件变量(QWaitCondition)讲解+QMutex实现多线程循环输出ABC(含源码+注释)
QSemaphore的使用+QSemaphore实现循环输出ABC(含源码+注释)
QRunnable线程、QThreadPool(线程池)的使用(含源码+注释)
Qt读写锁(QReadWriteLock)的使用、读写锁的验证(含源码+注释)
Qt读写锁(QWriteLocker、QReadLocker)的理解和使用(含部分源码)
Qt之线程运行指定函数(含源码+注释,优化速率)
友情提示——哪里看不懂可私哦,让我们一起互相进步吧
(创作不易,请留下一个免费的赞叭 谢谢 o/)
注:文章为作者编程过程中所遇到的问题和总结,内容仅供参考,若有错误欢迎指出。
注:如有侵权,请联系作者删除