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