百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术分析 > 正文

Qt进程和线程 qt多进程与多线程

liebian365 2024-10-17 13:59 51 浏览 0 评论

目录

1、进程

2、线程

1、进程

在设计一个应用程序时,有时不希望将一个不太相关的功能集成到程序中,或者是因为该功能与当前设计的应用程序联系不大,或者是因为该功能已经可以使用现成的程序很好的实现了,这时就可以在当前的应用程序中调用外部的程序来实现该功能,这就会使用到进程。Qt应用程序可以很容易的启动一个外部应用程序,而且Qt也提供了在多种进程间通信的方法。

Qt的QProcess类用来启动一个外部程序并与其进行通信。下面我们来看一下怎么在Qt代码中启动一个进程。

1.1、首先创建QtGui应用

工程名称为“myProcess”,其他选项保持默认即可。

1.2、然后设计界面

在设计模式往界面上拖入一个Push Button部件,修改其显示文本为“启动一个进程”。

1.3、修改槽

在按钮上点击鼠标右键,转到其clicked()信号对应的槽,更改如下:

void MainWindow::on_pushButton_clicked()
{
     myProcess.start("notepad.exe");
}

1.4、进入mainwindow.h文件添加代码

先添加头文件包含:#include <QProcess>,然后添加私有对象定义:QProcess myProcess;

1.5.运行程序

当单击界面上的按钮时就会弹出一个记事本程序。

这里我们使用QProcess对象运行了Windows系统下的记事本程序(即notepad.exe程序),因为该程序在系统目录中,所以这里不需要指定其路径。大家也可以运行其他任何的程序,只需要指定其具体路径即可。我们看到,可以使用start()来启动一个程序,有时启动一个程序时需要指定启动参数,这种情况在命令行启动程序时是很常见的,下面来看一个例子,还在前面的例子的基础上进行更改。

1.5.1、在mainwindow.h文件中添加代码。

添加私有槽:

private slots:
    void showResult();

1.5.2.在mainwindow.cpp文件中添加代码。

(1)先添加头文件包含:#include <QDebug>,然后在构造函数中添加如下代码:

connect(&myProcess,SIGNAL(readyRead()), this, SLOT(showResult()));

(2)然后添加showResult()槽的定义:

void MainWindow::showResult()
{
    qDebug() << "showResult: " << endl
            << QString(myProcess.readAll());
}

(3)最后将前面按钮的单击信号对应的槽更改为:

void MainWindow::on_pushButton_clicked()
{
    QString program = "cmd.exe";
    QStringList arguments;
    arguments << "/c dir&pause";
    myProcess.start(program, arguments);
}

这里在启动Windows下的命令行提示符程序cmd.exe时为其提供了命令作为参数,这样可以直接执行该命令。当命令执行完以后可以执行showResult()槽来显示运行的结果。这里为了可以显示结果中的中文字符,使用了QString()进行编码转换。这需要在mian()函数中添加代码。

【领QT开发教程学习资料,点击→「链接」←莬费领取,先码住不迷路~】

1.5.3. 为了确保可以显示输出的中文字符,在main.cpp文件中添加代码。

先添加头文件包含#include <QTextCodec>,然后在main()函数第一行代码下面,添加如下一行代码:

QTextCodec::setCodecForCStrings(QTextCodec::codecForLocale());

1.5.4.运行程序。

按下界面上的按钮,会在Qt Creator中的应用程序输出栏中输出命令的执行结果。

对于Qt中进程进一步的使用可以参考QProcess类的帮助文档。在Qt中还提供了多种进程间通信的方法,大家可以在Qt帮助中查看Inter-ProcessCommunication in Qt关键字对应的文档。


2、线程

Qt提供了对线程的支持,这包括一组与平台无关的线程类,一个线程安全的发送事件的方式,以及跨线程的信号-槽的关联。这些使得可以很容易的开发可移植的多线程Qt应用程序,可以充分利用多处理器的机器。多线程编程也可以有效的解决在不冻结一个应用程序的用户界面的情况下执行一个耗时的操作的问题。关于线程的内容,大家可以在Qt帮助中参考Thread Support in Qt关键字。

2.1、启动一个线程

Qt中的QThread类提供了平台无关的线程。一个QThread代表了一个在应用程序中可以独立控制的线程,它与进程中的其他线程分享数据,但是是独立执行的。相对于一般的程序都是从main()函数开始执行,QThread从run()函数开始执行。默认的,run()通过调用exec()来开启事件循环。要创建一个线程,需要子类化QThread并且重新实现run()函数。

每一个线程可以有自己的事件循环,可以通过调用exec()函数来启动事件循环,可以通过调用exit()或者quit()来停止事件循环。在一个线程中拥有一个事件循环,可以使它能够关联其他线程中的信号到本线程的槽上,这使用了队列关联机制,就是在使用connect()函数进行信号和槽的关联时,将Qt::ConnectionType类型的参数指定为Qt::QueuedConnection。拥有事件循环还可以使该线程能过使用需要事件循环的类,比如QTimer和QTcpSocket类等。注意,在线程中是无法使用任何的部件类的。

下面来看一个在图形界面程序中启动一个线程的例子,在界面上有两个按钮,一个用于开启一个线程,一个用于关闭该线程。

2.1.1.创建项目。

新建Qt Gui应用,名称为“myThread”,类名为“Dialog”,基类选择QDialog。

2.1.2.设计界面。

完成项目创建后进入设计模式,向界面中放入两个Push Button按钮,将第一个按钮的显示文本更改为“启动线程”,将其objectName属性更改为startButton;将第二个按钮的显示文本更改为“终止线程”,将其objectName属性更改为stopButton,将其enabled属性取消选中。

2.1.3.添加自定义线程类。

向项目中添加新的C++类,类名设置为“MyThread”,基类设置为“QThread”,类型信息选择“继承自QObject”。完成后进入mythread.h文件,先添加一个公有函数声明:

void stop();

然后再添加一个函数声明和一个变量的定义:

protected:
    void run();
private:
    volatile bool stopped;

这里stopped变量使用了volatile关键字,这样可以使它在任何时候都保持最新的值,从而可以避免在多个线程中访问它时出错。然后进入mythread.cpp文件中,先添加头文件#include <QDebug>,然后在构造函数中添加如下代码:

stopped = false;

这里将stopped变量初始化为false。下面添加run()函数的定义:

void MyThread::run()
{
    qreal i = 0;
    while (!stopped)
        qDebug() << QString("in MyThread: %1").arg(i++);
    stopped = false;
}

这里一直判断stopped变量的值,只要它为false,那么就一直打印字符串。下面添加stop()函数的定义:

void MyThread::stop()
{
    stopped = true;
}

在stop()函数中将stopped变量设置为了true,这样便可以结束run()函数中的循环,从而从run()函数中退出,这样整个线程也就结束了。这里使用了stopped变量来实现了进程的终止,并没有使用危险的terminate()函数。

.在Dialog类中使用自定义的线程。

先到dialog.h文件中,添加头文件包含:

#include "mythread.h"

然后添加私有对象的定义:

MyThread thread;

下面到设计模式,分别进入两个按钮的单击信号对应的槽,更改如下:

// 启动线程按钮

void Dialog::on_startButton_clicked()
{
    thread.start();
    ui->startButton->setEnabled(false);
    ui->stopButton->setEnabled(true);
}
// 终止线程按钮
void Dialog::on_stopButton_clicked()
{
    if (thread.isRunning()) {
        thread.stop();
        ui->startButton->setEnabled(true);
        ui->stopButton->setEnabled(false);
    }
}

在启动线程时调用了start()函数,然后设置了两个按钮的状态。在终止线程时,先使用isRunning()来判断线程是否在运行,如果是,则调用stop()函数来终止线程,并且更改两个按钮的状态。现在运行程序,按下“启动线程”按钮,查看应用程序输出栏的输出,然后再按下“终止线程”按钮,可以看到已经停止输出了。

下面我们接着来优化这个程序,通过信号和槽来将子线程中的字符串显示到主界面上。

A.在mythread.h文件中添加信号的定义:

signals:
void stringChanged(const QString &);

B.然后到mythread.cpp文件中更改run()函数的定义:

void MyThread::run()
{
    long int i = 0;
    while (!stopped) {
       QString str = QString("in MyThread: %1").arg(i);
       emit stringChanged(str);
       msleep(1000);
       i++;
    }
    stopped = false;
}

这里每隔1秒就发射一次信号,里面包含了生成的字符串。

C.到dialog.h文件中添加槽声明:

private slots:
    void changeString(const QString &);

D.打开dialog.ui,然后向主界面上拖入一个Label标签部件。

E.到dialog.cpp文件中,在构造函数里面添加信号和槽的关联:

// 关联线程中的信号和本类中的槽
connect(&thread, SIGNAL(stringChanged(QString)),
this, SLOT(changeString(QString)));

F.然后添加槽的定义:

void Dialog::changeString(const QString &str)
{
    ui->label->setText(str);
}

这里就是将子线程发送过来的字符串显示到主界面上。现在可以运行程序,查看效果了。

2.2、线程同步

Qt中的QMutex、QReadWriteLock、QSemaphore和QWaitCondition类提供了同步线程的方法。虽然使用线程的思想是多个线程可以尽可能的并发执行,但是总有一些时刻,一些线程必须停止来等待其他线程。例如,如果两个线程尝试同时访问相同的全局变量,结果通常是不确定的。QMutex提供了一个互斥锁(mutex);QReadWriteLock即读-写锁;QSemaphore即信号量;QWaitCondition即条件变量。

2.3、可重入与线程安全

在查看Qt的帮助文档时,在很多类的开始都写着“All functions in this class are reentrant”,或者“All functions in this class are thread-safe”。在Qt文档中,术语“可重入(reentrant)”和“线程安全(thread-safe)”用来标记类和函数,来表明怎样在多线程应用程序中使用它们:

一个线程安全的函数可以同时被多个线程调用,即便是这些调用使用了共享数据。因为该共享数据的所有实例都被序列化了。

一个可重入的函数也可以同时被多个线程调用,但是只能是在每个调用使用自己的数据时。

结语

最后要注意的是,使用线程是很容易出现问题的,比如无法在主线程以外的线程中使用GUI类的问题(可以简单的通过这样的方式来解决:将一些非常耗时的操作放在一个单独的工作线程中来进行,等该工作线程完成后将结果返回给主线程,最后由主线程将结果显示到屏幕上)。大家应该谨慎的使用线程。

相关推荐

4万多吨豪华游轮遇险 竟是因为这个原因……

(观察者网讯)4.7万吨豪华游轮搁浅,竟是因为油量太低?据观察者网此前报道,挪威游轮“维京天空”号上周六(23日)在挪威近海发生引擎故障搁浅。船上载有1300多人,其中28人受伤住院。经过数天的调...

“菜鸟黑客”必用兵器之“渗透测试篇二”

"菜鸟黑客"必用兵器之"渗透测试篇二"上篇文章主要针对伙伴们对"渗透测试"应该如何学习?"渗透测试"的基本流程?本篇文章继续上次的分享,接着介绍一下黑客们常用的渗透测试工具有哪些?以及用实验环境让大家...

科幻春晚丨《震动羽翼说“Hello”》两万年星间飞行,探测器对地球的最终告白

作者|藤井太洋译者|祝力新【编者按】2021年科幻春晚的最后一篇小说,来自大家喜爱的日本科幻作家藤井太洋。小说将视角放在一颗太空探测器上,延续了他一贯的浪漫风格。...

麦子陪你做作业(二):KEGG通路数据库的正确打开姿势

作者:麦子KEGG是通路数据库中最庞大的,涵盖基因组网络信息,主要注释基因的功能和调控关系。当我们选到了合适的候选分子,单变量研究也已做完,接着研究机制的时便可使用到它。你需要了解你的分子目前已有哪些...

知存科技王绍迪:突破存储墙瓶颈,详解存算一体架构优势

智东西(公众号:zhidxcom)编辑|韦世玮智东西6月5日消息,近日,在落幕不久的GTIC2021嵌入式AI创新峰会上,知存科技CEO王绍迪博士以《存算一体AI芯片:AIoT设备的算力新选择》...

每日新闻播报(September 14)_每日新闻播报英文

AnOscarstatuestandscoveredwithplasticduringpreparationsleadinguptothe87thAcademyAward...

香港新巴城巴开放实时到站数据 供科技界研发使用

中新网3月22日电据香港《明报》报道,香港特区政府致力推动智慧城市,鼓励公私营机构开放数据,以便科技界研发使用。香港运输署21日与新巴及城巴(两巴)公司签署谅解备忘录,两巴将于2019年第3季度,开...

5款不容错过的APP: Red Bull Alert,Flipagram,WifiMapper

本周有不少非常出色的app推出,鸵鸟电台做了一个小合集。亮相本周榜单的有WifiMapper's安卓版的app,其中包含了RedBull的一款新型闹钟,还有一款可爱的怪物主题益智游戏。一起来看看我...

Qt动画效果展示_qt显示图片

今天在这篇博文中,主要实践Qt动画,做一个实例来讲解Qt动画使用,其界面如下图所示(由于没有录制为gif动画图片,所以请各位下载查看效果):该程序使用应用程序单窗口,主窗口继承于QMainWindow...

如何从0到1设计实现一门自己的脚本语言

作者:dong...

三年级语文上册 仿写句子 需要的直接下载打印吧

描写秋天的好句好段1.秋天来了,山野变成了美丽的图画。苹果露出红红的脸庞,梨树挂起金黄的灯笼,高粱举起了燃烧的火把。大雁在天空一会儿写“人”字,一会儿写“一”字。2.花园里,菊花争奇斗艳,红的似火,粉...

C++|那些一看就很简洁、优雅、经典的小代码段

目录0等概率随机洗牌:1大小写转换2字符串复制...

二年级上册语文必考句子仿写,家长打印,孩子照着练

二年级上册语文必考句子仿写,家长打印,孩子照着练。具体如下:...

一年级语文上 句子专项练习(可打印)

...

亲自上阵!C++ 大佬深度“剧透”:C++26 将如何在代码生成上对抗 Rust?

...

取消回复欢迎 发表评论: