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

 

相关文章

Leave a Comment.