Bradley T. Hughes:You’re doing it wrong

我们广泛地使用IRC在自己与社会之间沟通。我挂出这个问题,希望可以帮助人们。一个常见的问题,我看到(同时这让我畏缩)人们了解和使用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来确保事件处理程序、扩展信号和槽从指定的线程调用。QThread是线程接口,所以要我们告诉线程来运行代码“本身”。我们要在线程运行之前做这些事情。上面这个例子,尽管这似乎工作,但这是令人困惑的也不是QThread设计的初衷(QThread中所有的函数是在QThread新创建的线程中定义和调用的,而不是在线程子类化的地方)。括号里这句话比较难理解,我个人参考了许多blog,认为:QThread子类化一个线程后,调用run()函数后,又新建了一个子进程,在子进程里调用相关的函数完成功能,再退出进程。言外之意就是,不要在子类化进程里定义成员,而是新建进程,在进程里调用子类化的QOject。


我觉得moveToThread(this)悄悄进入人们的代码,是因为他们在博客里有人用它。打开快速的网络搜索,打开了几个博客,他们都遵循下面的模式:

1、子类化QThread

2、添加signals和slots

3、测试,发现slots不是从正确的线程里调用

4、google一下,搜:moveToThread(this),有评论说添加这个后似乎可以工作


在我看来,这些问题从步奏1开始。QThread的设计的目的是作为一个操作系统线程的接口或者控制点,而不是用来堆放想要在一个thread实现的代码。在面向对象编程中,我们子类化,是因为我们想要扩展或者专用基类的功能。我能想到子类化QThread唯一有效的原因是增加QThread不具有的功能。比如提供一个指向内存的指针作为线程的堆栈

,或者增加实时接口/支持。对于下载文件、查询数据库或者其他不应该添加到QThread子类里的程序,都应该在自己的子类里封装。


通常这意味着,你要实现的类要继承自QObject而不是QThread。当你需要执行一些初始化工作时,QThread有一个started()信号可以供你connect。当你需要在新的线程里实现你的代码时,你可以实例化QThread,用moveToThread()函数把对象分配到该线程。即使你还在用moveToThread()告诉QT来执行你子类化QThread里的代码,我们也要保持线程接口的独立(这一句很难理解啊,是说子类化QThread不能有父对象吗?by  hustyangju 2013 - 07-26)。如果有必要,你可以给一个类的不同实例分配一个单一的线程,或者不同类的实例分配一个单一的线程。换句话说,把一个单一的实例绑定到一个线程是不必要的。


很多人对带线程的QT编程很困惑。早期版本的QThread是很抽象的,所以子类化是必要的。到了Qt4.4, QThread::run()默认实现了,不必再子类化了。在线程里不同对象可以通过信号和槽链接,因此在线程编程里有一种比较便捷的方法。






你可能感兴趣的:(subClass,Bradley,T.,QTread,Hughes)