QT之线程_qt线程启动的start函数可以带参吗-程序员宅基地

技术标签: QT  qt  线程  


一、QT中线程使用原则

在实际的开发中线程的使用频率很高,尤其是在开发界面程序的时候。QT的UI线程负责界面的事件相应,而一些复杂的逻辑运算可以放在一个子线程中进行。QT中线程的使用有一个原则,对于界面的操作只能在UI主线程中操作,子线程不能对UI界面进行操作。如果在子线程中需要对界面进行操作,可以使用信号通知UI主线程,由UI主线程进行操作。

二、QT中的线程

在QT中启动线程有三种方法:QThread、QtConcurrent::run、QRunnable

1、QThread

QThread是最为常用的启动线程的方法,QThread提供了一种独立管理线程的方法。QThread启动的线程从虚函数run()开始执行,所以通常在使用QThread启动线程时我们需要实现一个QThread的派生类,重写虚函数run(),在run()函数中现实子线程的代码。如果我们只需要把一个对象放在子线程中执行,没有复杂的操作代码,我们也可以使用Qobject::moveToThread函数,把对象移动到子线程中。

QThread对线程的管理

(1)线程启动

我们可以通过start()函数启动线程,start()函数有一个参数Priority线程的优先级,可参考enum QThread::Priority的取值,当线程已经被启动则调用此函数无任何作用。当调用此函数之后,会自动调用函数函数run(),所以run()函数是线程的线程函数

(2)线程停止

我们可以通过调用exit()或quit()函数停止线程。调用之后QEventLoop::exec()结束消息循环并返回,exec()返回exit()指定的返回码。通常为了方便,返回0为成功,负数为失败。quit()等同exit(0)。

也可以调用terminate()函数强制终止线程,需要调用setTerminationEnabled()设置线程为可被终止,但是也不一定会立即终止线程,这个要以来操作系统的调度策略。在terminate()之后使用wait()函数等待,确保线程结束。使用terminate()终止线程一个危险的操作,在程序的任何地方都可以调用此函数终止线程,可能这时线程在修改数据。终止时线程也未释放线程占用的资源(内存、线程锁....),所以之后在不是必须使用的时候,不建议使用

实例一 实现QThread的派生类:

class WorkerThread : public QThread
{
    Q_OBJECT
    void run() {
        QString result;
        /*线程执行的操作 */
        emit resultReady(result);
    }
signals:
    void resultReady(const QString &s);
};

void MyObject::startWorkInAThread()
{
    WorkerThread *workerThread = new WorkerThread(this);
    connect(workerThread, &WorkerThread::resultReady, this, &MyObject::handleResults);
    connect(workerThread, &WorkerThread::finished, workerThread, &QObject::deleteLater);
    workerThread->start();
}
实例二 特定对象在线程执行,使用moveToThread

class Worker : public QObject
{
    Q_OBJECT

public slots:
    void doWork(const QString ¶meter) {
        QString result;
        /* 线程执行的操作 */
        emit resultReady(result);
    }

signals:
    void resultReady(const QString &result);
};

class Controller : public QObject
{
    Q_OBJECT
    QThread workerThread;
public:
    Controller() {
        Worker *worker = new Worker;
        worker->moveToThread(&workerThread);
        connect(&workerThread, &QThread::finished, worker, &QObject::deleteLater);
        connect(this, &Controller::operate, worker, &Worker::doWork);
        connect(worker, &Worker::resultReady, this, &Controller::handleResults);
        workerThread.start();
    }
    ~Controller() {
        workerThread.quit();
        workerThread.wait();
    }
public slots:
    void handleResults(const QString &);
signals:
    void operate(const QString &);
};

注意:

每一个线程都有一个事件循环,使用QThread创建的线程同样也有一个事件循环。事件循环是信号和槽机制的重要组成部分,如果没有启动事件循环则信号与槽将不起作用。启动事件循环需要执行exec()函数,exec()函数是一个阻塞函数,而当我们派生QThread类重写run()函数时可能不想去执行exec(),因为这样最阻塞。这样就带来了一个问题,在线程中就不能使用信号与槽。如果我们需要在线程中使用信号与槽就必须执行exec()进行事件循环,这种情况可以采用实例二的方法,在封装一个线程操作对象,不进行重写run()函数而是对象在主线程中创建使用moveToThread()移动到子线程,这样在线程中就可以使用信号与槽,因为QThread::run()函数默认调用了exec()函数启动了事件循环

2、QtConcurrent::run

QtConcurrent命名空间里提供了一些高级API,利用这些API可以编写多线程程序,而不用直接使用比较低级的一些类,如mutext,lock, waitcondition以及semaphore等。使用QtConcurrent命令空间的API编写的程序会根据处理器的数目自动地调整线程的个数。QtConcurrent包含了用于并行列表处理的函数式编程,包含实现共享内存系统的MapReduce和FilterReduce, 以及管理GUI应用程序中异步计算的类。我们可以使用提供的run()函数,很方便的启动一个线程

using namespace QtConcurrent;  
void hello(QString name)  
{  
     qDebug() << "Hello" << name << "from" << QThread::currentThread();  
}  
int main(int argc, char **argv)  
{  
    QApplication app(argc, argv);  
    QFuture<void> f1 = run(hello, QString("Alice"));  
    QFuture<void> f2 = run(hello, QString("Bob"));  
    f1.waitForFinished();  
    f2.waitForFinished();  
    return app.exec();  
}
注意:同样存在在线程函数中不能使用信号与槽问题


3、QRunnable

作为Qt类中少有的基类, QRunnable提供了简洁有效的可运行对象的创建.  用QRunnable来创建独立的运行对象来运行 不涉及界面元素的数据处理过程 非常合适.

优点: 创建过程简洁, 使用方便, 配合着自身的autoDelete特性, 有点“招之即来, 挥之即去”的感觉.

缺点: 无法实时提供自身的运行状态,没有start函数,需要QThreadPool启动线程

默认情况,QThreadPool最在线程结束时自动删除QRunnable对象,我们也可以通过QRunnable::setAutoDelete()方法可以改变该默认行为。QThreadPool支持在QRunnable::run方法中通过调用tryStart(this)来多次执行相同的QRunnable。当最后一个线程退出run函数后,如果autoDelete启用的话,将删除QRunnable对象。在autoDelete启用的情况下,调用start()方法多次执行同一QRunnable会产生竞态,就避免这样做。那些在一定时间内会使用的线程将会过期。默认的过期时间是30秒。可通过setExpiryTimeout()方法来设置。设置一个负数的超时值代表禁用超时机制。方法maxThreadCount()可以查询可使用的最大线程数,你也可以设置最大的线程数。activeThreadCount反应的是当前正在被使用中的线程数个数。reserveThread函数保留某个线程为外部用,releaseThread释放该线程,这样就可以被再次使用。

class HelloWorldTask : public QRunnable
{
    void run()
    {
        qDebug() << "Hello world from thread" << QThread::currentThread();
    }
}
HelloWorldTask *hello = new HelloWorldTask();
// QThreadPool takes ownership and deletes 'hello' automatically
QThreadPool::globalInstance()->start(hello);


4、QThreadPool

QThreadPool管理一组线程。它负责管理和回收单个QThread对象以减少程序中线程创建的开销。每个Qt应用程序都有一个全局的QThreadPool对象,可通过方法globalInstance()获得。通常和QRunnable结合使用启动线程。在程序退出时也可以调用waitForDone()函数等待所有的线程退出





版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/yangguihao/article/details/48290129

智能推荐

Springboot中华非遗传承网站(附源码、论文)免费赠送项目完整源码,可做计算机毕业设计JAVA、PHP、爬虫、APP、小程序、C#、C++、python、数据可视化、大数据、全套文案等_bootstrap模板的岭南非遗文化网站-程序员宅基地

文章浏览阅读492次。中华非遗传承网站使用Java技术开发,SpringBoot框架,采用的数据库是Mysql。在设计过程中,充分保证了系统代码的良好可读性、实用性、易扩展性、通用性、便于后期维护、操作方便以及页面简洁等特点。_bootstrap模板的岭南非遗文化网站

进程间的几种通信方式_break shmget-程序员宅基地

文章浏览阅读131次。无名管道int pipe(int pipefd[2]);例:#include<sys/types.h>#include<unistd.h>#include<string.h>#include<stdio.h>#include<sys/wait.h>#include<stdlib.h>int main(){ int fd[2]; char buf[128]; pid_t pid; if(pipe(fd) == -_break shmget

gbq6的文件能转换成gbq5_pdf怎么转换成word?这些方法转换效果更佳-程序员宅基地

文章浏览阅读4.4k次。最近,不少朋友们给我留言,问题大概是如下这些:pdf怎么转换成word?如何把PDF文件转换为PPT?如何取出PDF文档中的某几页?如何把几个PDF文档合并成一个?排在首位最多人问的就是PDF转Word文档问题,由于PDF文件自身的一些性质,需要一些特殊的操作才能将其转换成Word格式,但很多普通转换的效果就没有我们想象的那么好了,但我们可以一步步找到最好的转换方法。复制粘贴法有些PDF文件是可以..._gbq6的文件怎么转换成word

Jmeter插件开发实现对mongo数据库的操作_jmeter mongodb返回dbcursor{collection=dbcollection{d-程序员宅基地

文章浏览阅读1.7k次。背景:使用JMeter做接口自动化,用例执行前需要清除一些数据,操作完后校验mongo数据。因为Jmeter3没有对Mongo数据库的支持,所以自己开发java请求实现对mongo的操作。1.eclipse新建java工程,依赖jar包如下2.写一个类实现连接mongo数据库,返回要操作的collection对象public DBCollection ConnectionMongoClient(S..._jmeter mongodb返回dbcursor{collection=dbcollection{database=db{name=''}}}

贪心之最小新整数_请编程完成以下任务: 1.从文件中读取闭区间的个数及它们的描述; 2.找到一个含元素-程序员宅基地

文章浏览阅读187次。贪心水题,每次把山峰删去,如果不存在山峰,则删去最后k个数字#include#includechar s[12];int main(){ int n; scanf("%d",&n); for(int q=0;q

java练习 二、判断语句 if--else语句_输入一个整数,如果此数为0,则输出”石头”,如果此数为1,则输出”剪刀”,如-程序员宅基地

文章浏览阅读2.5k次。1)接java练习 一、HelloWorld,地址:http://blog.csdn.net/u013871927/article/details/700576152)在src文件夹内创建IfPractice.java文件3)打开IfPractice.java,在里面编辑以下代码:public class IfPractice{public String practice(int_输入一个整数,如果此数为0,则输出”石头”,如果此数为1,则输出”剪刀”,如

随便推点

springboot145基于java的在线问卷调查系统的设计与实现_用java实现校友问卷调查管理系统-程序员宅基地

文章浏览阅读43次。MySQL的数据存放形式从大向小的说是数据库最大,然后是表,每个表里面存放数据是有一定的规则的,数据存放是表格形式的,也就是说有横也有竖,横着的为行,一般表示一条数据,每个表都有字段,而字段是以列的形式存在,这样能保证一条数据每一个字段对应的是相同数据类型的数据。传统处理数据,必须是一张张纸,然后处理完毕又是统计在一张张纸上面,不断的重复处理,最终有个结果给最高层作为参考,这个模式在互联网没有出现之前,是一种常见的事情,信息管理的效率提不上去,那就用人才,人多力量大,是一个以前人们的常识。_用java实现校友问卷调查管理系统

分布式数据库汇总_分布式数据库有哪些-程序员宅基地

文章浏览阅读4.1k次。1、 Apache HBase HBase :就是bigTable 支持数十亿列 Apache HBase是一个使用Java语言编写的、 以谷歌BigTable技术为基础的开源非关系型列式分布数据库, 可运行在HDFS文件系统之上。HBase提供了很好的存储容错能力和快速访问大量稀疏文件的能力。HBase遵循Apache 2许可证。Hbase的优点:1 列的可以动态增加, 并且列为空就..._分布式数据库有哪些

Mybatis-使用Maven建立Mybatis工程 (IDEA)_使用maven创建一个mybatis-程序员宅基地

文章浏览阅读4k次,点赞3次,收藏8次。使用IDEA创建Mybatis项目Mybatis应用的搭建流程 1. 创建一个maven项目 2. 添加Mybatis,MySQL驱动,junit依赖 3. 构建 4. 在src/main/resources添加一个mybatis-config.xml 5. 编写实体类,放在entity,实体类是跟我们数据库表对应的类 6. 编写映射,mapper包中,定一个m..._使用maven创建一个mybatis

Android毕设项目功能:商城列表与购物车展示(二)_搭构购物车列表条目android-程序员宅基地

文章浏览阅读2.8k次。在上一篇博客中,为大家展示了最终完成效果图,并且分析了界面之间的关系,以及每个界面布局结构中包含的控件信息,对于总体功能数据源进行了封装和介绍。并且重点说明了第一个界面商品分类界面的实现方法。在本篇博客中我们继续操作,完成具体分类的商品信息列表界面的展示。效果图如下:需求分析:此界面的布局结构为上中下结构,可使用线性布局进行排列,上半部分为标题栏,左右两个图标都具备点击功能,左边点击后..._搭构购物车列表条目android

R语言画图表_r语言图表-程序员宅基地

文章浏览阅读3.3k次。R 编程语言中有许多库用来创建图表,主要有6种图表1. 条形图条形图表示矩形条中的数据,其长度与变量的值成比例。R 使用 barplot()函数来创建条形图。R 可以在条形图中绘制垂直和水平条。在条形图中,每个条可以被赋予不同的颜色。语法使用 R 创建条形图的基本语法是barplot(H, xlab, ylab, main, names.arg, col)以下是使用的参数的描述:H..._r语言图表

Netty之线程唤醒wakeup [续]_netty wakeup-程序员宅基地

文章浏览阅读268次。在之前的Netty之线程唤醒wakeup文章中, 介绍了如何唤醒Netty中的监听线程. 接下来我们通过源码的角度,结合一些命令,看一下它的实现.// WakeUp.javaimport java.net.InetSocketAddress;import java.nio.channels.SelectionKey;import java.nio.channels.Selector;import java.nio.channels.ServerSocketChannel;import java._netty wakeup