Chinaunix首页 | 论坛 | 博客
  • 博客访问: 232582
  • 博文数量: 27
  • 博客积分: 270
  • 博客等级: 二等列兵
  • 技术积分: 444
  • 用 户 组: 普通用户
  • 注册时间: 2012-11-21 19:55
个人简介

Enjoy yourself!

文章分类

分类: C/C++

2015-12-31 16:51:16

    原来对QThread的理解,就是重写run(),曾经还一度搞不明白,到底它的槽属于主线程还是子线程。
    后来学了MFC,一度觉得MFC的机制比较人性化,起码有工作线程和界面线程的用法,而不像QThread只有run是真正活在子线程里面的。
    而直达今天再次研究QThread,发现QThread有很好的功能void QObject::moveToThread(QThread*);
先上代码:
widget.h

点击(此处)折叠或打开

  1. #ifndef WIDGET_H
  2. #define WIDGET_H

  3. #include <QWidget>
  4. #include <QDebug>
  5. #include <QThread>

  6. class QPushButton;

  7. namespace Ui {
  8. class Widget;
  9. }

  10. class myObject : public QObject
  11. {
  12.     Q_OBJECT
  13. public:
  14.     myObject() {}
  15.     ~myObject() {}

  16. public slots:
  17.     void first() 
  18.     {
  19.         qDebug()<< QThread::currentThreadId();
  20.     }
  21.     void second() 
  22.     {
  23.         qDebug()<< QThread::currentThreadId();
  24.     }
  25.     void third() 
  26.     {
  27.         qDebug()<< QThread::currentThreadId();
  28.     }
  29. };

  30. class Widget : public QWidget
  31. {
  32.     Q_OBJECT
  33.     
  34. public:
  35.     explicit Widget(QWidget *parent = 0);
  36.     ~Widget();
  37.     
  38. private:
  39.     Ui::Widget *ui;
  40.     myObject *my;
  41.     QPushButton *firstButton,*secondButton,*thirdButton,*selfButton;

  42. public slots:
  43.     void onFirstPushed();
  44.     void onSelfPushed();
  45. };

  46. #endif // WIDGET_H

widget.cpp

点击(此处)折叠或打开

  1. #include "widget.h"
  2. #include "ui_widget.h"
  3. #include <QVBoxLayout>
  4. #include <QPushButton>


  5. Widget::Widget(QWidget *parent) :
  6.     QWidget(parent),
  7.     ui(new Ui::Widget)
  8. {
  9.     ui->setupUi(this);
  10.     my = new myObject;
  11.     firstButton = new QPushButton(tr("firstBtn"), 0);
  12.     connect(firstButton, SIGNAL(clicked()), this, SLOT(onFirstPushed()));
  13.     secondButton = new QPushButton(tr("secondBtn"), 0);
  14.     connect(secondButton, SIGNAL(clicked()), my, SLOT(second()), Qt::DirectConnection);
  15.     thirdButton = new QPushButton(tr("thirdBtn"), 0);
  16.     connect(thirdButton, SIGNAL(clicked()), my, SLOT(third()), Qt::QueuedConnection);
  17.     selfButton = new QPushButton(tr("selfBtn"), 0);
  18.     connect(selfButton, SIGNAL(clicked()), this, SLOT(onSelfPushed()));

  19.     QVBoxLayout *layout = new QVBoxLayout;
  20.     layout->addWidget(firstButton);
  21.     layout->addWidget(secondButton);
  22.     layout->addWidget(thirdButton);
  23.     layout->addWidget(selfButton);

  24.     this->setLayout(layout);

  25.     QThread *thread = new QThread;
  26.     my->moveToThread(thread);
  27.     connect(thread, SIGNAL(started()), my, SLOT(first()));
  28.     thread->start();
  29. }

  30. Widget::~Widget()
  31. {
  32.     delete ui;
  33. }

  34. void Widget::onFirstPushed() 
  35. {
  36.     my->first();
  37. }

  38. void Widget::onSelfPushed() 
  39. {
  40.     qDebug() << QThread::currentThreadId();
  41. }
此代码参考自http://blog.csdn.net/sydnash/article/details/7425947 ,在度娘找的各种文章中,这篇算是最简洁易懂的,看了这篇再看其它都不成问题了。

    先说毫无疑问的两个功能:一是程序开始,线程启动,而my在线程中,my在线程中打印线程号;二是selfBtn,connect的槽函数完完全全属于主线程的函数,打印主线程线程号。
    接下来是三个重点的按钮,三个按钮的连接方式是不一样的。
    firstBtn连接的是主线程的槽函数,再在槽函数中执行first(),这样first()是在主线程中调用的,打印出来的是主线程的ID;
    secondBtn直接连接myObject中的槽函数,使用的是Qt:DirectConnection直接连接模式,此模式下信号与槽是同步的,信号发出后,直接在信号发送者线程中调用槽函数,由于信号是主线程发出的,因此打印的也是主线程的ID;
    thirdBtn也是直接连接myObject中的槽函数,但使用的是QT::QueuedConnection队列连接模式,此模式下信号与槽是异步的,信号发出后,会进入队列中,直到控制权到了接收对象(my)属于的线程(thread)的事件循环时,槽函数才被调用,因此此时打印的是子线程thread的线程ID。

    这里重点介绍下connect的第五个参数Qt::ConnectionType。此参数可以有三种选择Qt::AutoConnection、Qt::DirectConnection、Qt::QueuedConnection,分别是自动连接,直接连接和队列连接。正如上面所说,直接连接是同步的,槽函数将和信号同一线程,而队列连接是异步的,槽函数会属于接收对象所属线程。而自动连接是缺省选项,将自动选择直接连接和队列连接之一。而什么时候选择什么连接呢,发送者和接收者处于相同线程,选择直接连接;发送者和接收者处于不同线程,使用队列连接。(看过一篇很有趣的验证文,有兴趣可以参考http://www.cppblog.com/andreitang/archive/2011/08/26/154392.html)

    对于上面代码而言QPushButton的三个connect都属于发送者和接收者不在同一个线程,不使用第五个参数的情况下,是默认使用队列连接的,而thread的connect属于发送者和接收者在同一线程,都是thread的线程,默认使用直接连接。
ps:需要注意的是,虽然在connect时,my由主线程生成,还没moveToThread,还在主线程,但在运行时,信号发出的时候,my已经在子线程了,因此自动连接下还是会选择队列连接。自动连接的选择并不是在于对象生成的线程,而是在于对象所处的线程决定的。

    好了总结完毕,准备将线程加入到项目中。。。
End
阅读(7052) | 评论(0) | 转发(0) |
0

上一篇:MFC笔记:TCP Socket通信

下一篇:没有了

给主人留下些什么吧!~~