c/c++ console(控制台)编程详解。QT5 Thread线程。

前言:

QT5 Thread线程继承QThread方式

控制台文本窗口的决定是依据win32 api(win32
api可领略为微软于咱们提供的一模一样多元函数的聚合)实现的;

一.首先分析一下 QTimer Class与
Sleep()函数之间的私房

例1:

QTimer *t = new QTimer(*parent);
//创建QTimer 对象

#include <stdio.h>int main()
{
    printf("Hello World!\n");
    return 0;
}

t->start(_time);
//计时始每隔_time时间自动触发&QTimer::timeout信号

运作结果:

t->stop(); //结束计时

图片 1

Sleep()
//windows.h里面的系延时函数

例1中,我们就此printf()函数实现以决定高出口了hello
world!然而当我们怀念使拿事先输出的始末清除时,在stdio.h中的函数并无克满足我们的需求;这时我们就要借助win32
api函数

 

例2:

经上述措施实现案例:

#include <stdio.h>
#include <windows.h>
int main()
{
    printf("Hello World!\n");
    Sleep(1000);
    system("cls");
    return 0;
}

图片 2

运行结果:

//button 槽函数
void Widget::on_buttonstart_clicked()
{
    t->start(2000);
    Sleep(3000);
  qDebug() << "hello world!"; 
}

//timeout信号处理函数
connect(t, &QTimer::timeout,
            [=]()
    {
        ui->lcd_1->display(++i);
    });

图片 3

剖析,在无Sleep()函数的情况下:

例2中,用到windows.h中之Sleep();system();函数,Sleep(1000)函数功能也延时1s晚先后于下运作,system(“cls”)清除内容,所以于例2中,程序运行显示hello
world!一秒后就是排除

点击开始这在控制台显示hello world!;每隔2秒lcd显示+1;

用来控制高窗口操作的API函数如下:

起Sleep()的在后;点击开始先后本质是怀念每隔2秒lcd显示+1;3秒后控制台显示hello world!;

GetConsoleScreenBufferInfo 获得控制高窗口信息

图片 4

GetConsoleTitle 获得控制高窗口标题

终极结出是:

ScrollConsoleScreenBuffer 在缓冲区中倒数据块

点击开始,计时器计时,2秒晚,不运行connect();3秒后connect()第一潮运行;再过4秒,第二不好timeout信号触发,再次运行connect();

SetConsoleScreenBufferSize 更改指定缓冲区大小

末段显示结果也; 过时3秒制台显示hello world!lcd显示 1 再过时1秒显示2 更过2秒显示3 依次通过2秒示累加1;

SetConsoleTitle 设置控制高窗口标题

 

SetConsoleWindowInfo 设置控制高窗口信息

二.线程的引入;

例3:

 如果我们怀念要之结果是,点击按钮,lcd每一样秒显示+1,
3秒控制台回显hello world!  也就是Sleep(3000)显示hello
world!并无见面失去影响至Qtrimer计时;

#include <windows.h>
#include <stdio.h>

int main(void)

{
       SetConsoleTitle(L"hello world!"); // 设置窗口标题
       printf("hello world!");
       return 0;
}

 

运行结果:

 图片 5

图片 6

 单独创建线程A,在A线程是实现延时3秒输出hello
world!;

当例3中,我们利用了setconsoletitle()函数;窗口标题已然改变成hello
world!了

1.一个简练的支配台线程例子

关于任何函数的使用办法,可以度过,这里权且不做赘述了。。。。。

新建一个qt控制台程序 自定义一个接近 
这里虽让class mythread

 

//mythread.h

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class myThread: public QThread
{
public:
    myThread();
    void run(); //声明继承于QThread虚函数 run()
};

#endif // MYTHREAD_H 

//mythread.cpp

#include "mythread.h"
#include <QDebug>

myThread::myThread()
{

}
void myThread::run()
{
  qDebug() <<  "hello world!"; //复写QThread类的 run()函数
}

//main.cpp
#include <QCoreApplication>
#include "mythread.h"   //包涵头文件
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    myThread *thread1 = new myThread; //新建线程对象
    thread1->start();  //启动线程

    return a.exec();
}

1.控制台初始化

上例启动了一个新线程中输出hello
world!

 

改善上例:

#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
    //设置控制台窗口标题
    //SetConsoleTitle("更改标题字符串")
    SetConsoleTitleA("hello world!");

    //获取控制台窗口信息;
    //GetConsoleScreenBufferInfo(HANDLE hConsoleOutput, CONSOLE_SCREEN_BUFFER_INFO *bInfo)
    //第一个hConsoleOutput参数(标准控制句柄)通过GetStdHandle()函数返回值获得
    //第二个参数CONSOLE_SCREEN_BUFFER_INFO 保存控制台信息结构体指针
        /*数据成员如下:
        {
            COORD dwSize; // 缓冲区大小
            COORD dwCursorPosition; //当前光标位置
            WORD wAttributes; //字符属性
            SMALL_RECT srWindow; //当前窗口显示的大小和位置
            COORD dwMaximumWindowSize; //最大的窗口缓冲区大小
        }
        */
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_SCREEN_BUFFER_INFO bInfo;
    GetConsoleScreenBufferInfo(hOutput, &bInfo);
    cout << "窗口缓冲区大小:" << bInfo.dwSize.X << ", " << bInfo.dwSize.Y << endl;
    cout << "窗口坐标位置:" << bInfo.srWindow.Left << ", " << bInfo.srWindow.Top
         << ", "<< bInfo.srWindow.Right << ", " << bInfo.srWindow.Bottom << endl;

    //设置显示区域坐标
    //SetConsoleWindowInfo(HANDLE, BOOL, SMALL_RECT *);
    SMALL_RECT rc = {0,0, 79, 24}; // 坐标位置结构体初始化
    SetConsoleWindowInfo(hOutput,true ,&rc);
    cout << "窗口显示坐标位置:" << bInfo.srWindow.Left << ", " << bInfo.srWindow.Top
         << ", "<< bInfo.srWindow.Right << ", " << bInfo.srWindow.Bottom << endl;

    //更改指定缓冲区大小
    //SetConsoleScreenBufferSize(HANDLE hConsoleOutput, COORD dwSize)
    //COORD为一个数据结构体
    COORD dSiz = {80, 25};
    SetConsoleScreenBufferSize(hOutput, dSiz);
    cout << "改变后大小:" << dSiz.X << ", " << dSiz.Y << endl;

    //获取控制台窗口标题
    //GetConsoleTitle(LPTSTR lpConsoleTitle, DWORD nSize)
    //lpConsoleTitle为指向一个缓冲区指针以接收包含标题的字符串;nSize由lpConsoleTitle指向的缓冲区大小
    char cTitle[255];
    GetConsoleTitleA(cTitle, 255);
    cout << "窗口标题:" << cTitle << endl;

    // 关闭标准输出设备句柄
    CloseHandle(hOut);
    return 0;
}
//mythread.h
#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>

class myThread: public QThread
{
public:
    myThread();
    void run();
    QString name; //添加一个 name 对象
};

#endif // MYTHREAD_H

//mythread.cpp
#include "mythread.h"
#include <QDebug>

myThread::myThread()
{

}
void myThread::run()
{
  qDebug() <<  this->name << "hello world!";
    //添加一个for循环
  for(int i = 0; i < 1000; i++)
  {
      qDebug() << this->name << i;
  }
}

//main.cpp

#include <QCoreApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //连续创建三个子线程
    myThread *thread1 = new myThread;
    thread1->name = "mythred1";
    thread1->start();

    myThread *thread2 = new myThread;
    thread2->name = "mythred2";
    thread2->start();

    myThread *thread3 = new myThread;
    thread3->name = "mythred3";
    thread3->start();

    return a.exec();
}

运作结果:

运转结果:

图片 7

图片 8

 

结果显示输出为无序输出,结论三单线程完全独立运作,互不影响;

2.装文本属性(文本颜色、移动决定)

2.叔单线程,自然会生优先权的题目,也尽管是cpu,先运行哪个线程;下面给咱来讨论优先权

 

线程权限由线程启动函数start(Priority枚举)控制

#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
    /*设置文本属
    BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);//句柄, 文本属性*/

    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标准输出设备句柄
    WORD wr1 = 0xfa;//定义颜色属性;第一位为背景色,第二位为前景色
    SetConsoleTextAttribute(hOut, wr1);
    cout << "hello world!" << endl;

    WORD wr2 = FOREGROUND_RED | FOREGROUND_INTENSITY;//方法二用系统宏定义颜色属性
    SetConsoleTextAttribute(hOut, wr2);
    cout << "hello world!" << endl;

    /*移动文本位置位置
    BOOL ScrollConsoleScreenBuffer(HANDLE hConsoleOutput, CONST SMALL_RECT* lpScrollRectangle, CONST SMALL_RECT* lpClipRectangle,
                                   COORD dwDestinationOrigin,CONST CHAR_INFO* lpFill);
                                  // 句柄// 裁剪区域// 目标区域 // 新的位置// 填充字符*/
    //输出文本
    SetConsoleTextAttribute(hOut, 0x0f);
    cout << "01010101010101010101010101010" << endl;
    cout << "23232323232323232323232323232" << endl;
    cout << "45454545454545454545454545454" << endl;
    cout << "67676767676767676767676767676" << endl;

    SMALL_RECT CutScr = {1, 2, 10, 4}; //裁剪区域与目标区域的集合行成剪切区域
    SMALL_RECT PasScr = {7, 2, 11, 9}; //可以是NULL,即全区域
    COORD pos = {1, 8};     //起点坐标,与裁剪区域长宽构成的区域再与目标区域的集合为粘贴区

    //定义填充字符的各个参数及属性
    SetConsoleTextAttribute(hOut, 0x1);
    CONSOLE_SCREEN_BUFFER_INFO Intsrc;
    GetConsoleScreenBufferInfo(hOut, &Intsrc);
    CHAR_INFO chFill = {'A',  Intsrc.wAttributes}; //定义剪切区域填充字符
    ScrollConsoleScreenBuffer(hOut, &CutScr, &PasScr, pos, &chFill); //移动文本

    CloseHandle(hOut); // 关闭标准输出设备句柄
    return 0;
}

设若上例:在启动函数中进入枚枚量,具体参数可查阅帮助文档:

 

图片 9

运行结果:

3.QMutex

图片 10

QMutex类提供了线程之间的顾序列化。
QMutex的目的是保障目标,数据结构或代码段,以便同赖就来一个线程可以拜它(这同Java
synchronized关键字类似)。
QMutexLocker通常最好使用互斥锁,因为这么好挺轻地管锁定和解锁一致地实行。

WORD文本属性预定义宏:(可以直接用16进制表示,WORD w = 0xf0;前一位表示背景色,后一位代表前景色)
FOREGROUND_BLUE 蓝色
FOREGROUND_GREEN 绿色
FOREGROUND_RED 红色
FOREGROUND_INTENSITY 加强
BACKGROUND_BLUE 蓝色背景
BACKGROUND_GREEN 绿色背景
BACKGROUND_RED 红色背景
BACKGROUND_INTENSITY 背景色加强
COMMON_LVB_REVERSE_VIDEO 反色
当前文本属性信息可通过调用函数GetConsoleScreenBufferInfo后,在CONSOLE_SCREEN_ BUFFER_INFO结构成员wAttributes中得到。

在指定位置处写属性
    BOOL WriteConsoleOutputAttribute(HANDLE hConsoleOutput,  CONST WORD *lpAttribute, DWORD nLength,
                                    COORD dwWriteCoord, LPDWORD lpNumberOfAttrsWritten);
                                    //句柄, 属性, 个数, 起始位置, 已写个数*/
填充指定数据的字符
    BOOL FillConsoleOutputCharacter(HANDLE hConsoleOutput, TCHAR cCharacter,DWORD nLength, COORD dwWriteCoord,
                               LPDWORD lpNumberOfCharsWritten);
                               // 句柄, 字符, 字符个数, 起始位置, 已写个数*/
在当前光标位置处插入指定数量的字符
    BOOL WriteConsole(HANDLE hConsoleOutput, CONST VOID *lpBuffer, DWORD nNumberOfCharsToWrite,
                     LPDWORD lpNumberOfCharsWritten,LPVOID lpReserved);
                     //句柄, 字符串, 字符个数, 已写个数, 保留*/
向指定区域写带属性的字符
    BOOL WriteConsoleOutput(HANDLE hConsoleOutput, CONST CHAR_INFO *lpBuffer, COORD dwBufferSize,
                        COORD dwBufferCoord,PSMALL_RECT lpWriteRegion );
                        // 句柄 // 字符数据区// 数据区大小// 起始坐标// 要写的区域*/
在指定位置处插入指定数量的字符
    BOOL WriteConsoleOutputCharacter(HANDLE hConsoleOutput, LPCTSTR lpCharacter, DWORD nLength,
                                     COORD dwWriteCoord, LPDWORD lpNumberOfCharsWritten);
                                     // 句柄// 字符串// 字符个数// 起始位置// 已写个数*/
填充字符属性
    BOOL FillConsoleOutputAttribute(HANDLE hConsoleOutput, WORD wAttribute,DWORD nLength,
                                   COORD dwWriteCoord, LPDWORD lpNumberOfAttrsWritten);
                                   //句柄, 文本属性, 个数, 开始位置, 返回填充的个数*/

// 设置代码页,
SetConsoleOutputCP(437);如(简体中文) 设置成936
  int number = 6;

  void method1()
  {
      number *= 5;
      number /= 4;
  }

  void method2()
  {
      number *= 3;
      number /= 2;
  }

3.光标操作控制

 如果线程thread1 ,thread2分级顺序执行method1(),method2();最终结果以见面是:

#include <iostream>
#include <windows.h>
using namespace std;
int main()
{
    cout << "hello world!" << endl;

    //设置光标位置
    //SetConsoleCursorPosition(HANDLE hConsoleOutput,COORD dwCursorPosition);
    //设置光标信息
    //BOOL SetConsoleCursorInfo(HANDLE hConsoleOutput, PCONST PCONSOLE_CURSOR_INFO lpConsoleCursorInfo);
    //获取光标信息
    //BOOL GetConsoleCursorInfo(HANDLE hConsoleOutput,  PCONSOLE_CURSOR_INFO lpConsoleCursorInfo);
    //参数1:句柄;参数2:CONSOLE_CURSOR_INFO结构体{DWORD dwSize;(光标大小取值1-100)BOOL bVisible;(是否可见)}

    Sleep(2000);//延时函数
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    COORD w = {0, 0};
    SetConsoleCursorPosition(hOut, w);
    CONSOLE_CURSOR_INFO cursorInfo = {1, FALSE};
    Sleep(2000);//延时函数
    SetConsoleCursorInfo(hOut, &cursorInfo);
    CloseHandle(hOut); // 关闭标准输出设备句柄
    return 0;
}
 // method1()
  number *= 5;        // number is now 30
  number /= 4;        // number is now 7

  // method2()
  number *= 3;        // number is now 21
  number /= 2;        // number is now 10

运行结果:

number = 10;

输出hello
world!后延时星星秒,光标从第二实施移到行首,再2秒后光标隐藏不显得;

只是若线程1以行走常常,被系统挂载,或任何种种因素中延时运行,比如有重胜优先级线程申请运行,而线程2确并无被影响,最终结出用会见是:

4.键盘操作控制

  // Thread 1 calls method1()
  number *= 5;        // number is now 30

  // Thread 2 calls method2().
  //
  // Most likely Thread 1 has been put to sleep by the operating
  // system to allow Thread 2 to run.
  number *= 3;        // number is now 90
  number /= 2;        // number is now 45

  // Thread 1 finishes executing.
  number /= 4;        // number is now 11, instead of 10

 

此刻number = 11; 并不等于10;
同一程序运行不同结果,这是免容许的

#include <iostream>
#include <windows.h>
#include <conio.h>
using namespace std;
HANDLE hOut;
//清除函数
void cle(COORD ClPos)
{
    SetConsoleCursorPosition(hOut, ClPos);
    cout << "            " << endl;
}
//打印函数
void prin(COORD PrPos)
{
    SetConsoleCursorPosition(hOut, PrPos);
    cout << "hello world!" << endl;
}
//移动函数
void Move(COORD *MoPos, int key)
{
    switch(key)
    {
    case 72: MoPos->Y--;break;
    case 75: MoPos->X--;break;
    case 77: MoPos->X++;break;
    case 80: MoPos->Y++;break;
    default: break;
    }
}

int main()
{
    cout << "用方向键移动下行输出内容" << endl;
    hOut = GetStdHandle(STD_OUTPUT_HANDLE);//取句柄
    COORD CrPos = {0, 1};//保存光标信息
    prin(CrPos);//打印
    //等待键按下
    while(1)
    {
        if(kbhit())
        {
            cle(CrPos);//清除原有输出
            Move(&CrPos, getch());
            prin(CrPos);
        }
    }
    return 0;
}

这时即将靠QMutex 类;

 

 QMutex mutex;
  int number = 6;

  void method1()
  {
      mutex.lock();
      number *= 5;
      number /= 4;
      mutex.unlock();
  }

  void method2()
  {
      mutex.lock();
      number *= 3;
      number /= 2;
      mutex.unlock();
  }

运行结果:

当你当一个线程中调用lock()时,其他线程会待在和一个地方调用lock(),直到获得锁的线程调用unlock()。
lock()的一个非阻塞替代是tryLock()。
QMutex在不竞争状况下展开了优化。
如果该互斥体没有争用,则非递归QMutex将非分配内存。
它的构建和销毁几乎从来不开,这意味来广大互斥体作为其他类似的一样部分是充分好之。

图片 11

当线程1被cpu延时处理,而线程2甩卖及method2()时自动会进来method1()继续处理number
/=4;再返回method2();而此时而线程1继续执行时,自动又见面跻身到method2();

可以据此方向键任意运动hello
world!

4.QThread
起步暂停等待信号及槽控制实例

小心区分 getch();
getche(); getcher();函数

 延续控制台线程例子
在每个线程后面长 thread1->wait(); qDebug() << “hello world!”;

 

谅的结果以会是, 在线程输出了晚才会输出hello
world!

综合案例贪吃蛇,推箱子,俄罗斯方(待续。。。)

#include <QCoreApplication>
#include "mythread.h"
int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //连续创建三个子线程
    myThread *thread1 = new myThread;
    thread1->name = "mythred1";
    thread1->start();

    thread1->wait();
    qDebug() << "hello world!";

    return exec();
}

 现在反至GUI下,下面一个事例:

图片 12

//自定义线程类,头文件
#ifndef NITHREAD_H
#define NITHREAD_H

#include <QThread>

class nithread : public QThread
{
    Q_OBJECT
public:
    explicit nithread(QObject *parent = 0);
    bool stop;

signals:
    void sig(int);

protected:
    void run();

public slots:
};

#endif // NITHREAD_H 

//自定义线程类cpp
#include "nithread.h"
#include <QMutex>
nithread::nithread(QObject *parent) : QThread(parent)
{

}

void nithread::run()
{
    for(int i = 0; i < 100; i++)
    {
        QMutex mutex;
        mutex.lock();
        if(this->stop) break;
        mutex.unlock();
        emit sig(i);
        msleep(100);
    }
}

//GUi窗口类头文件
#ifndef DIALOG_H
#define DIALOG_H

#include <QDialog>
#include <nithread.h>

namespace Ui {
class Dialog;
}

class Dialog : public QDialog
{
    Q_OBJECT

public:
    explicit Dialog(QWidget *parent = 0);
    ~Dialog();

private slots:
    void on_buttonstart_clicked();
    void lot(int);

    void on_buttonstop_clicked();

private:
    Ui::Dialog *ui;
    nithread *threadd;
};

#endif // DIALOG_H

//GUI类cpp
#include "dialog.h"
#include "ui_dialog.h"

Dialog::Dialog(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::Dialog)
{
    ui->setupUi(this);
    threadd = new nithread(this);
    connect(threadd, SIGNAL(sig(int)), this, SLOT(lot(int)));
}

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

void Dialog::on_buttonstart_clicked()
{
    threadd->start();
}

void Dialog::lot(int num)
{
    ui->numberlabel->setText(QString::number(num));
}

void Dialog::on_buttonstop_clicked()
{
    threadd->stop = true;
}

//main.cpp
#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    Dialog w;
    w.show();

    return a.exec();
}

末尾结果:

当点击start 开启线程 stop 已线程
通过显号与槽显示结果

不过方法一Thread线程继承QThread方式,在事实上问题备受可有许多的题材如果下文简介:早于2006年既让qt工程师提出;(直指此方法是漏洞百出的用法)


咱(Qt用户)正广泛地应用IRC来开展交流。我于Freenode网站挂有了#qt标签,用于支援大家解答问题。我常常看到的一个题材(这叫我耐心),是关于理解Qt的线程机制和怎样让他们写的连锁代码是工作。人们贴出她们之代码,或者用代码写的范例,而己虽连接为如此的感动告终:

  • 你们还因此擦了!*

本人以为有件重要的业务得澄清一下,也许有些唐突了,然而,我只得指出,下面的斯(假想中之)类是针对性面向对象原则的不当使用,同样也是指向Qt的荒唐使用。

 

 

 

 

 

 

 

 

 

 

 

 

 

class MyThread : public QThread { public: MyThread() {
moveToThread(this); } void run(); signals: void progress(int); void
dataReady(QByteArray); public slots: void doWork(); void
timeoutHandler(); };

自身本着当下卖代码最充分之质询在 moveToThread(this);
 我表现了尽多人口这样使用,并且完全不理解她举行了头什么。那么您见面问,它究竟开了啊?moveToThread()函数通知Qt准备好事件处理程序,让扩展的信号(signal)和槽(slot)在指定线程的作用域中调用。QThread是线程的接口,所以我们是于报告这线程在“它其中”执行代码。我们呢应有在线程运行前举行这些事。即使这卖代码看起可运行,但其充分凌乱,并无是QThread设计受到的用法(QThread中描绘的富有函数都应以创造它的线程中调用,而不是QThread开启的线程)。

在自己的印象中,moveToThread(this);
 是以人们在少数文章被来看又采用要流传开来的。一不成飞跃的纱寻就可知找到此类文章,所有这些文章被还产生相近如下情形的段落:

  1. 继承QThread类
  2. 加加用来拓展工作的信号及槽
  3. 测试代码,发现槽函数并不曾以“正确的线程”中实行
  4. 谷歌一下,发现了moveToThread(this);
     然后形容及“看起的确管用,所以我长了这行代码”

我看,这些都自第一步。QThread是让设计来作为一个操作系统线程的接口及控制点,而无是因此来描写副你想当线程里实施的代码的地方。我们(面向对象程序员)编写子类,是坐咱们纪念扩大或者特化基类中之效果。我唯一想到的持续QThread类的成立原因,是加上QThread中莫分包的意义,比如,也许可以供一个内存指针来作线程的堆栈,或者好上加实时的接口及支撑。用于下载文件、查询数据库,或者开另外其它操作的代码都非应有叫加入到QThread的子类中;它应当为查封装在它好之目标被。

普通,你得省略地管看似从继续QThread改也持续QObject,并且,也许得改下类名。QThread类提供了start()信号,你得将它连接到你得之地方来拓展初始化操作。为了给您的代码实际运行于初线程的企图域中,你得实例化一个QThread对象,并且使用moveToThread()函数将公的靶子分配为其。你跟过moveToThread()来告诉Qt将公的代码运行在一定线程的图域中,让线程接口及代码对象分别。如果需要的话,现在公得用一个接近的大半个目标分配至一个线程中,或者将大半只类似的几近独目标分配至一个线程。换句话说,将一个实例与一个线程绑定并无是得的。


本身都听到了森有关编制Qt多线程代码时过度复杂的抱怨。原始的QThread类是抽象类,所以必须进行持续。但至了Qt4.4不再这样,因为QThread::run()有矣一个默认的落实。在头里,唯一采用QThread的法子尽管是继往开来。有矣线程关联性的支持,和信号槽连接机制的扩充,我们发矣平等种更加有利地运线程的法门。我们喜爱便利,我们纪念使她。不幸的凡,我尽晚地意识及事先迫使人们连续QThread的做法被新的道重新麻烦推广。

自也听到了一部分埋怨,是关于无共同创新范例程序及文档来为众人展示什么用最无令人头疼的法子方便地进行支付的。如今,我能够引用的极品的资源是自数年前写的一致首博客。()


免责声明:你所看到底地方的整,当然还只是个人观点。我于这些看似点花费了不少生气,因此关于要什么样以和毫无争以它,我具备一定清楚的想法。


译者注:

新颖的Qt帮助文档同时提供了树QThread实例和继续QThread的一定量种植多线程实现方式。根据文档描述和范例代码来拘禁,若想以子线程中运用信号槽机制,应运用分别树QThread和目标实例的计;若仅是独自想用子线程运行阻塞式函数,则可连续QThread并再写QThread::run()函数。

由后续QThread后,必须在QThread::run()函数中显调用QThread::exec()来提供对信息循环机制的支撑,而QThread::exec()本身会死调用方线程,因此对此欲以子线程中使信号槽机制的事态,并无引进下持续QThread的款型,否则程序编写会较为复杂。


于Qt4.4开始,可以使用新的不二法门为是受喻为是的方式也是qt想放的方法:

// Worker 类定义 cpp
 #include <QtCore>  
    class Worker : public QObject  
    {  
        Q_OBJECT  
    private slots:  
        void onTimeout()  
        {  
            qDebug()<<"Worker::onTimeout get called from?: "<<QThread::currentThreadId();  
        }  
    };  

//main函数cpp

    int main(int argc, char *argv[])  
    {  
        QCoreApplication a(argc, argv);  
        qDebug()<<"From main thread: "<<QThread::currentThreadId();  

        QThread t;  
        QTimer timer;  
        Worker worker;  

        QObject::connect(&timer, SIGNAL(timeout()), &worker, SLOT(onTimeout()));  
        timer.start(1000);  

        worker.moveToThread(&t);  

        t.start();  

        return a.exec();  
    }  

总结:

连续QThread老式方法

1.定义继承QThread的类A
复写run()函数;

2.以主线程遭遇实例化A对象a

3.通过调用a->start()启动线程,线程会自动调用run()虚函数;run不可直接调用;

新方法:

1.开立继承Obeject的类A
将要在线程中贯彻之计以A类吃落实

2.当主线程中实例化A对象a,再实例化QThread类对象b

3.由此a.moveToThread(&b);将a对象的贯彻移入线程b对象作用范围外运行

4.b->start()启动线程;

5.透过信号和槽的主意启动调用A类成员函数;

常用函数:

QThread类

start(),//启动线程;

wait()//等线程运行了;

quit(),//线程运行了退出线程

 

相关文章