qt中线程的运用方式,QT的经过与线程

QT中选用线程能够增强工效。

该文章原创于Qter开源社区(www.qter.org卡塔 尔(英语:State of Qatar),我yafeilinux,转发请注脚出处!

要动用线程要通过一下多个步骤:

导语

(1卡塔 尔(阿拉伯语:قطر‎先创制三个c++ class文件,记得世襲Thread,创设步骤如下:


          a、第一步

在日前的几节内容中等教育授了Qt互联网编制程序的某些中坚内容,这黄金年代节来看一下在Qt中经过和线程的基本接受。

        图片 1

 

        b、第二步

 

         图片 2

 

 

环境:Windows Xp + Qt 4.8.5+Qt Creator2.8.0

                 图片 3

目录

 


(2卡塔 尔(阿拉伯语:قطر‎自定义三个run函数,现在运营线程的时候,程序就能够跳转到run函数中

一、进程

void run();

二、线程

(3卡塔尔开端化线程

正文

HDThread mythread = new HDThread();

(4卡塔 尔(英语:State of Qatar)运行线程

 

mythread->start();

一、进程

 

 

上边来探视界程使用的实际列子:

 
  在统筹二个应用程序时,一时不愿意将二个不太相关的信守集成到程序中,或然是因为该意义与眼下两全的应用程序联系非常小,只怕是因为该意义已经能够选择现存的前后相继很好的达成了,那个时候就能够在时下的应用程序中调用外界的主次来兑现该功效,那就能够利用到进程。Qt应用程序能够相当轻巧的启航八个外界应用程序,何况Qt也提供了在各类进程间通讯的章程。

线程头文件hdthread.h:

   
Qt的QProcess类用来运营一个外部程序并与其進展通讯。上面大家来看一下怎么在Qt代码中运营二个历程。

 1 #ifndef HDTHREAD_H
 2 #define HDTHREAD_H
 3 #include <QThread>
 4 #include <QLabel>
 5 #include <QMutex>
 6 
 7 class HDTHread : public QThread
 8 {
 9 public:
10     HDTHread(QMutex* mtex,QObject *parent = 0);
11     void run();//自定义的run函数
12     void setLabel(QLabel *lb);
13 private:
14     QLabel *label;
15     QMutex *mutex; //互斥锁
16 };
17 
18 #endif // HDTHREAD_H

 

主函数的头文件threadqt.h

 

 1 #ifndef THREADQT_H
 2 #define THREADQT_H
 3 
 4 #include <QMainWindow>
 5 #include <hdthread.h>
 6 #include <writefile.h>
 7 #include <QMutex>
 8 #include <QSemaphore>
 9 
10 namespace Ui {
11 class ThreadQt;
12 }
13 
14 class ThreadQt : public QMainWindow
15 {
16     Q_OBJECT
17 
18 public:
19     explicit ThreadQt(QWidget *parent = 0);
20     ~ThreadQt();
21 
22      //定义静态的信号类
23     static QSemaphore *sp_A;
24     static QSemaphore *sp_B;
25 private slots:
26     void on_pushButton_clicked();
27 
28 private:
29     Ui::ThreadQt *ui;
30 
31     HDTHread *thread; //hdtread类,里面继承了线程
32     WriteFile *writethread;
33     QMutex mutex;//定义互斥锁类
34 
35 };
36 
37 #endif // THREADQT_H

1.首先创设QtGui应用。

 

工程名叫“myProcess”,其余选择保持暗中同意就能够。

 

 

源文件hdthread.cpp:

 

#include "hdthread.h"
#include <QDebug>
#include <threadqt.h>
HDTHread::HDTHread(QMutex *mtex, QObject *parent):QThread(parent)//构造函数,用来初始化
{
    this->mutex = mtex;
}
void HDTHread::setLabel(QLabel *lb)
{
    this->label = lb;
}

void HDTHread::run() //启动线程时执行的函数
{
    while(true)
    {

        qint64 data = qrand()%1000; //取随机数
        //this->mutex->lock();//上锁
        ThreadQt::sp_A->acquire();//请求信号
        this->label->setText(QString::number(data));
         sleep(1);
        ThreadQt::sp_B->release();//释放信号
        //this->mutex->unlock();//解锁

        qDebug()<<"hello Qt"<<data;
    }
}

2.然后规划分界面。

源文件threadqt.cpp

在设计方式往界面上拖入八个Push
Button构件,改过其出示文本为“运营三个历程”。

#include "threadqt.h"
#include "ui_threadqt.h"

//初始化静态变量
 QSemaphore *ThreadQt::sp_A = NULL;
 QSemaphore *ThreadQt::sp_B = NULL;

ThreadQt::ThreadQt(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::ThreadQt)
{
    ui->setupUi(this);
    //创建信号对象
    sp_A = new QSemaphore(1);
    sp_B = new QSemaphore(0);

}

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

void ThreadQt::on_pushButton_clicked()
{
    thread = new HDTHread(&mutex); //初始化线程
    thread->setLabel(ui->label);
    thread->start();//开启线程

    writethread = new WriteFile(&mutex);
    writethread->setLabel(ui->label);
    writethread->start();
}

 

 

 

大家也看出了,此处的线程也运用了互斥锁(复信号量卡塔尔国有限支撑线程读写多少时不出新谬误,这里我们能够看一下实际贯彻的代码

3.修改槽。

this->mutex->lock();//上锁
ThreadQt::sp_A->acquire();//请求信号
this->label->setText(QString::number(data));
sleep(1);
ThreadQt::sp_B->release();//释放信号
this->mutex->unlock();//解锁

在按键上点击鼠标右键,转到其clicked()功率信号对应的槽,校正如下:

 

void MainWindow::on_pushButton_clicked()

{

     myProcess.start(“notepad.exe”);

}

 

 

4.进来mainwindow.h文件加多代码。

先加多头文件包涵:#include
<QProcess>,然后加多个人对象定义:QProcess myProcess;

 

 

5.运作程序。

当单击分界面上的按键时就能弹出三个记事本程序。

 

 

此地我们应用QProcess对象运维了Windows系统下的记事本程序(即notepad.exe程序卡塔 尔(阿拉伯语:قطر‎,因为该程序在系统目录中,所以那边无需内定其路线。我们也得以运作别的任何的主次,只必要钦定其实际渠道就能够。大家见到,能够应用start()来运维二个顺序,偶然运转一个前后相继时供给钦赐运营参数,这种状态在命令行运转程序时是很广阔的,上面来看一个例子,还在前面包车型大巴例证的根基上开展转移。

 

 

1.在mainwindow.h文件中增添代码。

增多私有槽:

private slots:

    void showResult();

 

 

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()函数中加多代码。

 

 

3. 为了保险可以展现输出的汉语字符,在main.cpp文件中增多代码。

先增加头文件包罗#include
<QTextCodec>,然后在main()函数第风流浪漫行代码下边,增加如下大器晚成行代码:

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

 

 

4.运作程序。

 

按下分界面上的按键,会在Qt Creator中的应用程序输出栏中输出命令的实施结果。

 

 
  对于Qt中经过进一层的选择能够参见QProcess类的赞助文书档案。在Qt中还提供了二种进度间通讯的办法,我们能够在Qt援救中查看Inter-ProcessCommunication
in Qt关键字对应的文书档案。

 

 

二、线程

 

   

Qt提供了对线程的支撑,那包含生机勃勃组与平台毫无干系的线程类,贰个线程安全的发送事件的法子,以至跨线程的非确定性信号-槽的涉嫌。那几个使得可以十分轻巧的费用可移植的八线程Qt应用程序,能够足够利用多微型机的机械。多线程编制程序也能够使得的解决在不冻结三个应用程序的客户分界面包车型客车情形下施行三个耗费时间的操作的难题。关于线程的内容,我们能够在Qt扶植中参阅Thread
Support in Qt关键字。

 

 

(风度翩翩卡塔尔运转贰个线程

 

   
Qt中的QThread类提供了阳台毫不相关的线程。二个QThread代表了三个在应用程序中得以独自操纵的线程,它与经过中的其余线程分享数据,可是是单身实施的。相对于日常的次序都以从main()函数开端执行,QThread从run()函数开始实践。私下认可的,run()通过调用exec()来展开事件循环。要开创一个线程,必要子类化QThread而且重新落成run()函数。

 
  每一个线程能够有投机的风波循环,能够通过调用exec()函数来运转事件循环,能够透过调用exit()或许quit()来终止事件循环。在多少个线程中兼有四个事件循环,能够使它能够关联其余线程中的实信号到本线程的槽上,那使用了队列关联机制,正是在动用connect()函数实行实信号和槽的涉嫌时,将Qt::ConnectionType类型的参数钦定为Qt::QueuedConnection。具有事件循环还足以使该线程能过使用要求事件循环的类,譬喻QTimer和QTcpSocket类等。注意,在线程中是敬谢不敏使用别的的构件类的。

 
  上边来看三个在图形分界面程序中运转三个线程的例证,在分界面上有七个开关,八个用于开启叁个线程,多个用来关闭该线程。

 

 

1.创办项目。

    新建Qt Gui应用,名称叫“myThread”,类名称为“Dialog”,基类接收QDialog。

 

 

2.企划界面。

    落成项目开创后跻身设计情势,向界面中归入三个Push
Button开关,将第二个开关的显得文本改善为“运转线程”,将其objectName属性纠正为startButton;将第四个按键的体现文本改革为“终止线程”,将其objectName属性改正为stopButton,将其enabled属性撤销选中。

 

 

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()函数。

 

 

4.在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()函数来终止线程,并且校勘三个按键的景况。今后运路程序,按下“运维线程”开关,查看应用程序输出栏的出口,然后再按下“终止线程”开关,能够看看曾经告生龙活虎段落输出了。

 
  上面大家跟着来优化那些程序,通过数字信号和槽来将子线程中的字符串展现到主分界面上。

 

 

1.在mythread.h文件中增多非确定性信号的定义:

signals:

void stringChanged(const QString &);

 

 

2.然后到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秒就发出三遍复信号,里面含有了调换的字符串。

 

 

3.到dialog.h文件中加多槽声称:

private slots:

    void changeString(const QString &);

 

 

4.开发dialog.ui,然后向主分界面上拖入叁个Label标签构件。

 

 

5.到dialog.cpp文件中,在构造函数里面增多功率信号和槽的涉及:

// 关联线程中的实信号和本类中的槽

connect(&thread, SIGNAL(stringChanged(QString)),

this, SLOT(changeString(QString)));

 

 

6.然后增加槽的概念:

void Dialog::changeString(const QString &str)

{

    ui->label->setText(str);

}

 
  这里正是将子线程发送过来的字符串显示到主分界面上。以往得以运路程序,查看效果了。

 

 

(二卡塔 尔(阿拉伯语:قطر‎线程同步

 

   
Qt中的QMutex、QReadWriteLock、QSemaphore和QWaitCondition类提供了黄金时代道线程的措施。即便使用线程的合计是三个线程能够尽也许的面世实施,不过总有点全日,一些线程必须截止来等待别的线程。比方,假设五个线程尝试同不常间做客同后生可畏的全局变量,结果日常是不鲜明的。QMutex提供了叁个互斥锁(mutex卡塔尔;QReadWriteLock即读-写锁;QSemaphore即时限信号量;QWaitCondition即标准变量。

 

 

(三卡塔尔国可重入与线程安全

 

在翻看Qt的扶持文书档案时,在大多类的起首都写着“All functions in this class
are reentrant”,或许“All functions in this class are
thread-safe”。在Qt文书档案中,术语“可重入(reentrant卡塔 尔(英语:State of Qatar)”和“线程安全(thread-safe卡塔 尔(英语:State of Qatar)”用来标志类和函数,来表达如何在多线程应用程序中央银行使它们:

  • 三个线程安全的函数可以况兼被七个线程调用,即就是这一个调用使用了分享数据。因为该分享数据的有着实例都被类别化了。
  • 一个可重入的函数也得以同临时候被八个线程调用,不过只可以是在种种调用使用本身的数额时。

 

 

 

结语


 

最终要细心的是,使用线程是十分轻便出现难题的,例如不能在主线程以外的线程中接受GUI类的难题(能够省略的通过那样的不二秘技来消除:将有个别不胜耗时的操作放在贰个单身的行事线程中来拓宽,等该工作线程完结后将结果再次回到给主线程,最终由主线程将结果显示到显示屏上卡塔 尔(英语:State of Qatar)。我们应该深谋远虑的利用线程。

 

 

http://blog.csdn.net/an505479313/article/details/48494901