(十七)线程,connect的第五个参数
采用多线程,将需要处理的后台数据放入子线程,为了能够跨线程调用,一种方法是使用类似线程锁对线程进行保护,另外一种方法使用Qt的信号槽机制。Qt的信号槽机制采用connect函数进行连接,connect函数其实是有第五个参数的,但这个参数往往在多线程调用中才会用到:
connect(Sender,SIGNAL(signal),Receiver,SLOT(slot),Qt::DirectConnection);
1
第五个参数代表槽函数在哪个线程中执行 :
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 = ;
ui->lcdNumber->display(num++);
}); connect(ui->begin, &QPushButton::clicked, this, [=](){
if(mytimer->isActive() == true)
{
return;
}
// 启动定时器
mytimer->start(); // ms // 启动线程
myt->start();
}); connect(myt,&MyThread::sigDone,mytimer,&QTimer::stop);
} MyWidget::~MyWidget()
{
delete ui;
}
MyWidget.cpp
#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
MyWidget.h
#include "mythread.h" MyThread::MyThread(QObject *parent) : QThread(parent)
{ } void MyThread::run()
{
// 复杂的操作
sleep();
emit sigDone();
}
MyThread.cpp
#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
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();
// 4. 启动子线程
pthread->start(); // 发信号, 让子线程工作
emit sigWorking();
} void MyWidget::slotStop()
{
mytimer->stop();
} void MyWidget::slotTimeout()
{
static int num = ;
ui->lcdNumber->display(num++);
} void MyWidget::slotCloseThread()
{
mywork->setFlage(true); pthread->quit();
pthread->wait(); // 等待线程手头上的工作处理完成
}
mywidget.cpp
#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
mywidget.h
#include "mywork.h"
#include <QDebug> MyWork::MyWork(QObject *parent) : QObject(parent)
{
isStop = false;
} void MyWork::doMyWork()
{
while(!isStop)
{
// 操作
QThread::sleep(); // 当前线程处理操作用了1s
// 每执行一次循环发一次信号
emit sigDone();
qDebug() << QThread::currentThread() << "sub thread";
// QMessageBox::aboutQt(NULL);
if(isStop)
{
break;
}
}
} void MyWork::setFlage(bool bl)
{
isStop = bl;
}
mywork.cpp
#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:
private:
bool isStop; }; #endif // MYWORK_H
mywork.h
(十七)线程,connect的第五个参数的更多相关文章
- QT信号槽connect的第五个参数
用过QT的小伙伴都知道连接信号槽的connect方法,但是这个方法有第五个参数,一般都是用的默认的 connect(th,SIGNAL(started()),tmpmyobject,SLOT(show ...
- C#语法——泛型的多种应用 C#语法——await与async的正确打开方式 C#线程安全使用(五) C#语法——元组类型 好好耕耘 redis和memcached的区别
C#语法——泛型的多种应用 本篇文章主要介绍泛型的应用. 泛型是.NET Framework 2.0 版类库就已经提供的语法,主要用于提高代码的可重用性.类型安全性和效率. 泛型的定义 下面定义了 ...
- Thread之一:线程生命周期及五种状态
<Thread之一:线程生命周期及五种状态> <juc线程池原理(四): 线程池状态介绍> 一.线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较 ...
- C#线程安全使用(五)
CancellationToken的多种应用 这是线程安全的最后一篇了,主要介绍CancellationToken的多种应用. 1,ThreadPool直接启动线程,传递CancellationTo ...
- 对线程等待函数pthread_join二级指针参数分析
分析之前先搞明白,这个二级指针其实在函数内部是承接了上个线程的返回值. 看man手册,发现返回值是个普通指针.人家用二级指针来承接,可能准备干大事.这个可以自己搜索一下.原因嘛,二级指针是保存了这个地 ...
- SpringMVC详解(五)------参数绑定
参数绑定,简单来说就是客户端发送请求,而请求中包含一些数据,那么这些数据怎么到达 Controller ?这在实际项目开发中也是用到的最多的,那么 SpringMVC 的参数绑定是怎么实现的呢?下面我 ...
- python接口自动化(十五)--参数关联接口(详解)
简介 我们用自动化新建任务之后,要想接着对这个新建任务操作,那就需要用参数关联了,新建任务之后会有一个任务的Jenkins-Crumb,获取到这个Jenkins-Crumb,就可以通过传这个任务Jen ...
- Java线程的周期及五种状态
线程的生命周期及五种基本状态 关于Java中线程的生命周期,首先看一下下面这张较为经典的图: 上图中基本上囊括了Java中多线程各重要知识点.掌握了上图中的各知识点,Java中的多线程也就基本上掌握了 ...
- Java项目性能瓶颈分析及定位(八)——Java线程堆栈分析(五)
对于CPU而言,常见的瓶颈主要有两种:服务器的压力很小,但是CPU的利用率却很高,这样的性能瓶颈相对比较容易定位(好比我只是说了你一句,你就哭了,你的弱点立马就暴露出来了):给服务器施加的压力很大,但 ...
随机推荐
- 高深的dp POJ 2229Sumsets
对于这个问题, 我们显然可以看出来, 当他是奇数的时候, 直接等于他的前一个偶数 dp [ i ] = dp [ i - 1] ; 那么问题, 当它是偶数的时候, 我们应该怎么进行 dp 记忆化搜索并 ...
- python — mysql基础知识
目录 1 . 数据库的介绍 2. mysql 1 . 数据库的介绍 1.为什么要用数据库? 很多功能如果只是通过操作文件来改变数据是非常繁琐的,程序员需要做很多事情 对于多台机器或者多个进程操作用一份 ...
- C#之Action和Func
以前我都是通过定义一个delegate来写委托的,但是最近看一些外国人写的源码都是用action和func方式来写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间来学习下这两种方式,然后发 ...
- 函数——箭头函数&自执行函数(二)
一.箭头函数是在es6中添加的一种规范,它相当于匿名函数,简化了函数的定义. 1.语法 a.function用var,let,cost来表示: b.参数要写在第一个等号后面: 参数有多个,需要加一 ...
- div 清除浮动的四种方法
概述:为了解决父级元素因为子级内部高度为0的问题 (很多情况 不方便给父级元素高,因为不知道有多少内容,让里面的盒子自动撑起高度),清除浮动本质叫闭合浮动更好一些,清除浮动就是把浮动的盒子关到里面,让 ...
- ASR测试方法---字错率(WER)、句错率(SER)统计
一.基础概念 1.1.语音识别(ASR) 语音识别(speech recognition)技术,也被称为自动语音识别(英语:Automatic Speech Recognition, ASR), 狭隘 ...
- Spring Cloud(O)服务的注册与发现(Eureka)
一.微服务架构 1.1什么是分布式 不同模块部署在不同服务器上 作用:分布式解决网站高并发带来问题 1.2什么是集群 多台服务器部署相同应用构成一个集群 作用:通过负载均衡设备共同对外提供服务 1.3 ...
- JavaMaven【八、pom.xml】
简介: 重点学习: 1.dependency-scope 依赖范围 compile 编译 默认,对编译.测试.运行都有效 provided 编译和测试时有效 runtime 测试和运行时有效 test ...
- oracle内核参数详解
一.前言 在生产中,我们安装oracle数据库时,为达到最优我们需要对操作系统的内核参数进行一定的调整.主要从内存.cpu.io以及网络等方面,根据实际情况进行调整.以下参数可供大家参考,如有不当之处 ...
- pip安装tesserocr时报错
在Xubuntu上的python2虚拟环境中, 使用pip安装tesserocr时报错error: command 'x86_64-linux-gnu-gcc' failed with exit st ...