添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

Qt线程-connect的第五个参数

采用多线程,将需要处理的后台数据放入子线程,为了能够跨线程调用,一种方法是使用类似线程锁对线程进行保护,另外一种方法使用Qt的信号槽机制。Qt的信号槽机制采用connect函数进行连接,connect函数其实是有第五个参数的,但这个参数往往在多线程调用中才会用到:

connect(Sender,SIGNAL(signal),Receiver,SLOT(slot),Qt::DirectConnection);


第五个参数代表槽函数在哪个线程中执行 :
1) 自动连接(AutoConnection) ,默认的连接方式,如果信号与槽,也就是发送者与接受者在同一线程,等同于直接连接;如果发送者与接收者处在不同线程,等同于队列连接。


2) 直接连接(DirectConnection) ,当信号发射时,槽函数立即直接调用。无论槽函数所属对象在哪个线程,槽函数总在发送者所在线程执行,即槽函数和信号发送者在同一线程


3) 队列连接(QueuedConnection) ,当控制权回到接受者所在线程的事件循环时,槽函数被调用。槽函数在接受者所在线程执行,即槽函数与信号接受者在同一线程


4)锁定队列连接(QueuedConnection)
Qt::BlockingQueuedConnection: 槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。 接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。


5)单一连接(QueuedConnection)
Qt::UniqueConnection: 这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接


如果槽函数中有耗时操作,比如说while循环,主线程的信号子线程是不会响应的,除非使用直接连接(DirectConnection),connect(this, &Controller::kill, worker, &Worker::stopWork, Qt::DirectConnection);,此时,槽函数工作于主线程。
下面是一个简单的多线程例子: (Qt有两种多线程的方法,其中一种是继承QThread的run函数,另外一种是把一个继承于QObject的类转移到一个Thread里。 Qt4.8之前都是使用继承QThread的run这种方法,但是Qt4.8之后,Qt官方建议使用第二种方法。两种方法区别不大,用起来都比较方便,但 继承QObject的方法更加灵活 。)

QT4.7版本以前线程的使用



#include "mywidget.h"
#include "ui_mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
    ui->setupUi(this);
    mytimer = new QTimer(this);
    myt = new MyThread(this);
    connect(mytimer,&QTimer::timeout,this,[=](){
       static int num = 0;
       ui->lcdNumber->display(num++);
    connect(ui->begin, &QPushButton::clicked, this, [=](){
        if(mytimer->isActive() == true)
            return;
        // 启动定时器
        mytimer->start(500); // ms
        // 启动线程
        myt->start();
    connect(myt,&MyThread::sigDone,mytimer,&QTimer::stop);
MyWidget::~MyWidget()
    delete ui;
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QTimer>
#include "mythread.h"
namespace Ui {
class MyWidget;
class MyWidget : public QWidget
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
private:
    Ui::MyWidget *ui;
    QTimer *mytimer;
    MyThread* myt;
#endif // MYWIDGET_H
#include "mythread.h"
MyThread::MyThread(QObject *parent) : QThread(parent)
void MyThread::run()
    // 复杂的操作
    sleep(5);
    emit sigDone();
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
#include <QThread>
class MyThread : public QThread
    Q_OBJECT
public:
    explicit MyThread(QObject *parent = nullptr);
protected:
    void run(); // 入口函数 -- 需要start()启动
signals:
    void sigDone();
public slots:
#endif // MYTHREAD_H



QT4.7版本之后线程的使用

/* 多线程使用注意事项:
     * 1. 业务对象, 构造的时候不能指定父对象
     * 2. 子线程中不能处理ui窗口(ui相关的类)
     * 3. 子线程中只能处理一些数据相关的操作, 不能涉及窗口
/* connect 的第 5 参数
     * 1. 自动连接 -- 默认
     *      多线程 -- 指定队列连接
     *      单线程 -- 指定直接连接
     * 2. 队列连接 -- 多线程
     *      槽函数在信号接受者(receiver)所在的线程中执行
     * 3. 直接连接 -- 单线程
     *      信号和槽函数在同一个线程中执行
#include "mywidget.h"
#include "ui_mywidget.h"
MyWidget::MyWidget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::MyWidget)
    ui->setupUi(this);
    mytimer  = new QTimer(this);
    // 1. 业务对象
    mywork = new MyWork();
    // 2. 子线程类
    pthread = new QThread(this);
    // 3. 移动业务对象到子线程
    mywork->moveToThread(pthread);
    // 5. 子线程工作
    connect(this, &MyWidget::sigWorking, mywork, &MyWork::doMyWork);
    connect(ui->begin, &QPushButton::clicked, this, &MyWidget::slotStart);
    connect(ui->stop, &QPushButton::clicked, this, &MyWidget::slotStop);
    // 定时器
    connect(mytimer, &QTimer::timeout, this, &MyWidget::slotTimeout);
    connect(this,&MyWidget::destroyed, this, &MyWidget::slotCloseThread);
MyWidget::~MyWidget()
    delete ui;
void MyWidget::slotStart()
    if(mytimer->isActive() == true)
        return;
    if(pthread->isRunning())
        return;
    mytimer->start(500);
    // 4. 启动子线程
    pthread->start();
    // 发信号, 让子线程工作
    emit sigWorking();
void MyWidget::slotStop()
    mytimer->stop();
void MyWidget::slotTimeout()
    static int num = 0;
    ui->lcdNumber->display(num++);
void MyWidget::slotCloseThread()
    mywork->setFlage(true);
    pthread->quit();
    pthread->wait();    // 等待线程手头上的工作处理完成
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QTimer>
#include "mywork.h"
#include <QThread>
namespace Ui {
class MyWidget;
class MyWidget : public QWidget
    Q_OBJECT
public:
    explicit MyWidget(QWidget *parent = nullptr);
    ~MyWidget();
    // 开始按钮
    void slotStart();
    // 关闭按钮
    void slotStop();
    // 定时器
    void slotTimeout();
    // 关闭线程
    void slotCloseThread();
signals:
    void sigWorking();
private:
    Ui::MyWidget *ui;
    QTimer* mytimer;
    MyWork* mywork;
    QThread* pthread;
#endif // MYWIDGET_H
#include "mywork.h"
#include <QDebug>
MyWork::MyWork(QObject *parent) : QObject(parent)
    isStop = false;
void MyWork::doMyWork()
    while(!isStop)
        // 操作
        QThread::sleep(1);  // 当前线程处理操作用了1s
        // 每执行一次循环发一次信号
        emit sigDone();
        qDebug() << QThread::currentThread() << "sub thread";
        // QMessageBox::aboutQt(NULL);
        if(isStop)
            break;
void MyWork::setFlage(bool bl)
    isStop = bl;
#ifndef MYWORK_H
#define MYWORK_H
#include <QObject>
#include <QThread>
class MyWork : public QObject
    Q_OBJECT
public:
    explicit MyWork(QObject *parent = nullptr);
    // 业务处理函数
    void doMyWork();
    void setFlage(bool bl);
signals:
    void sigDone();
public slots: