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(),//线程运行了退出线程

 

相关文章