先后就会跳转到run函数中,这时就足以在脚下的应用程序中调用外部的次序来落实该意义

QT中选拔线程可以抓好工作作用。

该小说原创于Qter开源社区(www.qter.org),小编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)启动线程

 

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。拥有事件循环还足以使该线程能过使用需求事件循环的类,比如Q提姆er和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)”和“线程安全(thread-safe)”用来标记类和函数,来申明如何在二十四线程应用程序中应用它们:

  • 一个线程安全的函数可以而且被多少个线程调用,即使是这几个调用使用了共享数据。因为该共享数据的所有实例都被系列化了。
  • 一个可重入的函数也能够同时被八个线程调用,可是只好是在种种调用使用自己的数码时。

 

 

 

结语


 

最终要留意的是,使用线程是很不难出现难点的,比如无法在主线程以外的线程中动用GUI类的标题(能够大概的经过如此的措施来解决:将部分分外耗时的操作放在一个单独的做事线程中来开展,等该工作线程已毕后将结果回到给主线程,最终由主线程将结果展现到屏幕上)。我们应该深思熟虑的运用线程。

 

 

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

相关文章