【问题标题】:use QThread exclusively for an object专门为一个对象使用 QThread
【发布时间】:2012-12-30 17:33:55
【问题描述】:

EDIT2

这是解决以下问题的解决方案,即专门为对象提供 QThread。

我已经改变了解决问题的方法。我不想再关闭 MyClass 中的 QThread,因为下面的解决方案看起来更简单,看起来也不错。

我的解决方案是修改这里给出的解决方案:http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/

该解决方案的问题在于 QObject worker 并没有真正被删除(检查过)。

QThread *myThread = new QThread();
SCIntermediary* myObj = new MyClass();
myObj->moveToThread(myThread);
connect(myThread, SIGNAL(started()), myObj, SLOT(setup()));
connect(myObj, SIGNAL(destroyed()), myThread, SLOT(quit()), Qt::DirectConnection);
connect(myObj, SIGNAL(finished()), myObj, SLOT(deleteLater()));
connect(myThread, SIGNAL(finished()), myThread, SLOT(deleteLater()));
myThread -> start();

// do your work bla bla bla

myObj -> finishIt(); // this function only emits finish() signal of myObj
myThread -> wait();

这是第一个对我有用的解决方案,它可以完全销毁 myObj 和 myThread,而没有任何错误或其他麻烦。

ENDOF 编辑

我正在尝试创建一个类,它将在我的客户端和服务器之间做一些事情。我希望它有自己的线程。所以我做的是:

class Myclass : public QObject {
    Q_OBJECT
public:
    Myclass();
    ~Myclass();

private:
    QThread *my_thread;
    QTcpSocket *sock;
}

这是我编写构造函数的方式:

Myclass::Myclass(){
    my_thread = new QThread();
    my_thread -> start();
    moveToThread(my_thread);

    sock = new QTcpSocket(this);
    sock -> connectToHost("host", port);
}

这不起作用。它不起作用,因为 TcpSocket 的代码没有在父对象当前所在的同一线程中执行。所以我决定做的是为设置创建插槽和信号,并在我的构造函数中发出它。这是我的代码现在的样子。

class Myclass : public QObject {
    Q_OBJECT
public:
    Myclass();
    ~Myclass();

public slots:
    void setup();

signals:
    void do_setup();

private:
    QThread *my_thread;
    QTcpSocket *sock;
}

还有一些实现

Myclass::Myclass(){
    my_thread = new QThread();
    my_thread -> start();
    moveToThread(my_thread);

    connect(this, SIGNAL(do_setup()), this, SLOT(setup()));
    emit do_setup();
}

void Myclass::setup(){
    sock = new QTcpSocket();
    sock -> connectToHost("host", port);
}

现在它起作用了,可悲的部分来了 - 看起来很糟糕!这太糟糕了,我不知道如何让它看起来更好,或者首先应该如何完成这种模式。你会建议我做什么来获得同样的效果?

另外 - 我不知道如何为此编写好的析构函数 - 如何顺利删除 QThread 和所有类对象..

编辑

目前我认为解决方案还不错——剩下的唯一问题是如何为此编写析构函数。我不知道如何在这里完成。

【问题讨论】:

  • 是的,不再推荐继承QThread,参见Qt文档
  • 出于好奇,如果您在原始示例中使用 moveToThread(my_thread); 放置的位置,它会改变什么吗?比如说,如果您将该语句作为构造函数的最后一行 - 那么您将对象及其所有子对象移动到新线程后,一旦它完全构造?或者,就在连接套接字之前但在创建之后?
  • @IlyaKobelevskiy qt-project.org/doc/qt-4.8/qthread.html:“详细说明”和“注释(页面底部)”
  • 对于析构函数,请查看 Maya Posch 示例 - mayaposch.wordpress.com/2011/11/01/… 由于您的线程不是 MyClass 的子线程,也许您可​​以在析构函数中将线程作为第一件事完成,并将完成的信号连接到 deleteLater 线程?跨度>
  • 有一些示例说明如何在不继承 QThread 的情况下正确执行此操作。您应该将自定义插槽连接到线程启动和停止时发出的信号......然后启动线程。线程发出的信号将调用槽并且仍然在该线程中。不要对该主线程中的对象执行任何其他操作。

标签: multithreading qt qthread qt4.8


【解决方案1】:

对于析构函数,请查看 Maya Posch 示例: http://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/ 由于您的线程不是 MyClass 的子线程,也许您可​​以将线程上的 finish() 作为析构函数中的最后一件事调用,并将 MyClass 的 destroy() 信号连接到线程的 deleteLater?

【讨论】:

  • 是的,这正是我现在所做的 - 只有一个更正 - 你需要将该连接作为 DirectConnection 来在你正在关闭的线程上调用它(实际上它调用了退出,并在线程调用时完成了它稍后删除)。
  • @Gricha myObj->destroyed()myThread->quit() 之间的 Qt::DirectConnection 是允许的,因为 quit() 是线程安全的。您直接从 myThread->thread() 以外的线程调用 myThread 的函数,这通常是不安全的。
【解决方案2】:

您可以使用QMetaObject::invokeMethod http://qt-project.org/doc/qt-4.8/qmetaobject.html#invokeMethod 而不是使用信号

QMetaObject::invokeMethod(this, "setup", Qt::QueuedConnection);

但这仍然很重,但我想这是更好的选择......如果有人有更好的想法,请评论:-)

【讨论】:

  • 我喜欢它——它需要信号破解。我同意这仍然不是解决方案,但我们更接近它;)谢谢
【解决方案3】:

这个怎么样,我认为在连接之前手动将套接字移动到新创建的线程应该可以工作,因为两个对象都应该在新创建的同一个线程中?

Myclass::Myclass()
{
    my_thread = new QThread();
    my_thread -> start();
    moveToThread(my_thread);

    sock = new QTcpSocket(this);
    sock -> moveToThread(my_thread);
    sock -> connectToHost("host", port);
}

【讨论】:

  • 这行不通。假设你现在在线程 A 中。您正在将此对象移动到线程 B。但该方法仍在线程 A 中。因此您试图在线程 A 中创建一个套接字,并且作为父级您给它一些属于线程 B 的东西。您不能这样做。您将得到的错误是:QObject: Cannot create children for a parent that is in a different thread.
猜你喜欢
  • 1970-01-01
  • 2013-10-18
  • 2017-12-17
  • 1970-01-01
  • 2011-11-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多