这个时候就能够在时下的应用程序中调用外界的次第来落到实处该功效,程序就能够跳转到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(卡塔尔(英语:State of Qatar)槽来显示运营的结果。这里为了能够来得结果中的中文字符,使用了QString(卡塔尔国进行编码变换。那需求在mian(卡塔尔(英语:State of Qatar)函数中增多代码。

 

 

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代表了二个在应用程序中得以独自垄断(monopoly卡塔尔(قطر‎的线程,它与经过中的别的线程分享数据,然则是独自实行的。相对于平日的主次都以从main(卡塔尔(英语:State of Qatar)函数最早实践,QThread从run(卡塔尔函数开始实践。默许的,run(卡塔尔国通过调用exec()来开启事件循环。要创设贰个线程,须要子类化QThread何况重新实现run(卡塔尔(قطر‎函数。

 
  每一个线程能够有和好的平地风波循环,能够通过调用exec(卡塔尔函数来运行事件循环,能够经过调用exit(卡塔尔(英语:State of Qatar)恐怕quit(卡塔尔(قطر‎来终止事件循环。在一个线程中兼有叁个平地风波循环,能够使它能够关联别的线程中的能量信号到本线程的槽上,那使用了队列关联机制,正是在利用connect(卡塔尔(英语:State of Qatar)函数实行能量信号和槽的关系时,将Qt::ConnectionType类型的参数钦点为Qt::QueuedConnection。具备事件循环还是可以使该线程能过使用须要事件循环的类,比如QTimer和QTcpSocket类等。注意,在线程中是回天无力运用任何的零件类的。

 
  上面来看二个在图形界面程序中运行一个线程的例证,在分界面上有多少个按键,三个用于开启二个线程,叁个用来关闭该线程。

 

 

1.创办项目。

    新建Qt Gui应用,名叫“myThread”,类名字为“Dialog”,基类选拔QDialog。

 

 

2.设计界面。

    完结项目开创后步向设计方式,向分界面中放入七个Push
Button开关,将率先个开关的体现文本改过为“运行线程”,将其objectName属性校正为startButton;将第1个按键的显得文本纠正为“终止线程”,将其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(卡塔尔(英语:State of Qatar)函数中的循环,进而从run(卡塔尔函数中分离,那样任何线程也就终止了。这里运用了stopped变量来落实了经过的苏息,并从未使用危殆的terminate(卡塔尔(英语:State of Qatar)函数。

 

 

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(卡塔尔(英语:State of Qatar)函数的定义:

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即读-写锁;Q塞马phore即非信号量;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

相关文章