栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

Qt互斥QMutex,QMutexLocker

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Qt互斥QMutex,QMutexLocker

发帖记录。

Qt帮助

qt帮助写得很容易懂,但仅仅是个示例,跟实际运行还是有区别的。

QMutex mutex;
  int number = 6;

  void method1()
  {
      mutex.lock();
      number *= 5;
      number /= 4;
      mutex.unlock();
  }

  void method2()
  {
      mutex.lock();
      number *= 3;
      number /= 2;
      mutex.unlock();
  }

Then only one thread can modify number at any given time and the result is correct. 
This is a trivial example, of course, but applies to any other case where things
need to happen in a particular sequence.
When you call lock() in a thread, other threads that try to call lock() in the same 
place will block until the thread that got the lock calls unlock(). A non-blocking 
alternative to lock() is tryLock().

跟网上大多代码一样,看起来清晰,但不能直接这样用。上面写了,这是要运行在两个线程当中的。所以并不是两个方法调用一个变量。

我做了一个小例子想验证一下。

思路

界面上读入一个整型数字。

线程1执行:加1,再乘2。线程2执行:乘2,再加1。

每一步都sleep一会儿,输出结果分析执行过程。

界面

很简单就是一个按钮用来启动线程,把执行的结果加载到列表中观察。

 clear按钮用来清空列表,上面的文本框用来输入数字,随便就好。

代码结构

 见名知意。

mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include 
#include 
#include 

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = 0);
    ~MainWindow();

private slots:
    void on_pushButton_clicked();
    void on_Update(QString s);

    //响应线程发来的消息,用于更新界面
    void on_pushButton_2_clicked();

private:
    Ui::MainWindow *ui;

    //运行于主线程中的变量,不能写在按钮槽中,否则不能滞留内存,达不到效果
    int m_i;

    //互斥对象,两个线程要公用一个才有效果
    QMutex m_mutex;

};

#endif // MAINWINDOW_H
mainwindow.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::on_pushButton_clicked()
{
    //从文本框读入数字
    m_i = ui->lineEdit->text().toInt();

    //创建子线程,线程重写了构造函数,用于传送变量,我使用了指针,希望指向同一内存
    Thread1 *thd1 = new Thread1(&m_i);
    Thread2 *thd2 = new Thread2(&m_i);
    
    //绑定信号与槽,用于子线程向主线程发结果更新界面
    connect(thd1, SIGNAL(sigUpdate(QString)), this, SLOT(on_Update(QString)));
    connect(thd2, SIGNAL(sigUpdate(QString)), this, SLOT(on_Update(QString)));
    
    //使用成员变量,把互斥对象传给子线程,这里传的是地址,我希望确实操作的是同一个对象
    thd1->m_mutex = &m_mutex;
    thd2->m_mutex = &m_mutex;

    thd1->start();
    thd2->start();

    ui->textEdit->append("---------------------------");
}

void MainWindow::on_Update(QString s)
{
    ui->textEdit->append(s);
}

void MainWindow::on_pushButton_2_clicked()
{
    ui->textEdit->clear();
}
thread1.h
#ifndef THREAD1_H
#define THREAD1_H

#include 
#include    

class Thread1 : public QThread
{
    Q_OBJECT
public:
    explicit Thread1(int *i);
    QMutex *m_mutex;

protected:
    void run();
    int *m_i;

private:

signals:
    //定义信号,用于向主线程发送结果,更新界面
    void sigUpdate(QString s);
};

#endif // THREAD1_H
thread1.cpp
#include "thread1.h"

Thread1::Thread1(int *i)
{
    m_i = i;
}

void Thread1::run()
{
    (*m_mutex).lock();//对象指针也可以这样写:m_mutex->lock();

    *m_i += 1;

    //发信号,用于向主线程发送结果,更新界面
    emit sigUpdate("Thread1: i + 1 = " + QString::number(*m_i));

    msleep(500);

    *m_i *= 2;

    //发信号,用于向主线程发送结果,更新界面
    emit sigUpdate("Thread1: i * 2 = " + QString::number(*m_i));

    msleep(500);

    (*m_mutex).unlock();//对象指针也可以这样写:m_mutex->unlock();
}
thread2.h
#ifndef THREAD2_H
#define THREAD2_H

#include 

class Thread2 : public Thread1//直接从thread1继承了一个
{
    Q_OBJECT
public:
    explicit Thread2(int *i);//因为thread1重写的构造函数,这里必须显式继承构造函数
protected:
    void run();
};

#endif // THREAD2_H
thread2.cpp
#include "thread2.h"

Thread2::Thread2(int *i):Thread1(i)//显式继承构造函数,注意参数传递方式
{}
void Thread2::run()
{
    (*m_mutex).lock();//对象指针也可以这样写:m_mutex->lock();

    *m_i *= 2;

    //发信号,用于向主线程发送结果,更新界面
    emit sigUpdate("Thread2: i * 2 = " + QString::number(*m_i));  
  
    msleep(500);

    *m_i += 1;

    //发信号,用于向主线程发送结果,更新界面
    emit sigUpdate("Thread2: i + 1 = " + QString::number(*m_i));

    msleep(500);

    (*m_mutex).unlock();//对象指针也可以这样写:m_mutex->unlock();
}

验证结果

首先注释掉代码中所有(*m_mutex).lock();和(*m_mutex).unlock();运行之后,文本框输入数字“1”,执行begin按钮。

 很明显,两个线程异步执行,变量i的数值没有规律。

接着,去掉代码中所有(*m_mutex).lock();和(*m_mutex).unlock();的注释,再运行。

启用QMutex之后,两个线程不会互相穿插执行了。要么执行直到完毕,要么等待另一个线程完成再开始。

这就是互斥的效果。当两个线程共享内存时,可以实现独占的效果。

QMutexLocker

看看qt帮助就知道。

Locking and unlocking a QMutex in complex functions and statements or in exception handling code is error-prone and difficult to debug. QMutexLocker can be used in such situations to ensure that the state of the mutex is always well-defined.

QMutexLocker should be created within a function where a QMutex needs to be locked. The mutex is locked when QMutexLocker is created. You can unlock and relock the mutex with unlock() and relock(). If locked, the mutex will be unlocked when the QMutexLocker is destroyed.

This example function will get more complicated as it is developed, which increases the likelihood that errors will occur.

Using QMutexLocker greatly simplifies the code, and makes it more readable:...

Now, the mutex will always be unlocked when the QMutexLocker object is destroyed (when the function returns since locker is an auto variable).

大概意思就是,遇到使用Mutex比较麻烦复杂的时候,使用QMutexLocker可以简化代码,方法就是把QMutexLocker放在局部使用,执行时启用lock,不用时自动unlock。

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/883403.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号