【问题标题】:Qt slot argument is corruptedQt 插槽参数已损坏
【发布时间】:2016-04-19 10:48:15
【问题描述】:

原来的代码太大了,贴在这里。基本上,我正在这样做:

class MySuperClass 
{
    QThread thread;
    MyClass myObject;

    MySuperClass() 
    {

        connect( this, &MySuperClass::onKill, &myObject, &MyClass::stop );

        connect( &thread, &QThread::started, &myObject, &MyClass::loop );
        connect(&myObject, &MyClass::finished, &thread, &QThread::quit );

        myObject.moveToThread( &thread );

        qRegisterMetaType<uint16_t>("uint32_t");

        connect( this, &MySuperClass::changed, &myObject, &MyClass::onChange );
    }

    void do()
    {
        emit changed(0);
    }
}

'onKill - stop' 信号/槽没有参数并且工作正常。这里没问题。

问题是“已更改 - onChange”对。他们有一个 uint32_t 类型的参数(我已经注册过)。

当我从主线程调用 MySuperClass 的方法 do 时,信号被发出,插槽 onChange 被调用,但它的参数不是 0! 这是一个像 3043426304 这样的大数字。

有趣的是:如果我将连接类型更改为 DirectConnection - 参数为零;如果我将连接类型更改为 QueuedConnection - 参数也为零!怎么会这样? AutoConnection 不是 Queued 还是 Direct?

我对此感到非常困惑。首先:堆栈分配的整数类型参数如何被破坏?我会理解它是堆分配的还是在多个线程中使用的。

我的第二个问题是:我应该如何正确地进行这种连接? connect 和 moveToThread 的顺序重要吗?

【问题讨论】:

  • 有些奇怪:qRegisterMetaType("uint32_t");那不应该是 qRegisterMetaType("uint32_t");
  • ChrisG 可能已经指出了您的问题(此处为 +1)。但是,您可以使用 quint32(它可以与 uint32_t 互换),但它是预先注册的,因此您可以避免必须注册它并且难以发现错误:)
  • @ChrisG riiight,我太傻了!愚蠢的复制粘贴错误。我没有注意到 3043426304 在两个最低有效位中有零。谢谢!您能否将您的评论作为答案,以便我接受? (尽管我仍然对 moveToThread 和 connect 调用的排序感兴趣)。
  • @code_fodder 我真的不明白为什么每个人都必须为固定长度类型创建自己的 typedef。 Qt 中有 quint32,Glib 中有 guint32,uC/OS 中有 SINT32 - 如果有 standart 类型定义,为什么还要麻烦?
  • @Amomum 好吧,它只是一个 Qt 的东西,这样你就可以得到一个“免费注册”的类型。但我完全同意你的看法,我总是在任何地方使用 uint16_t 。但是在 Qt 中,使用其内置类型时,您会少一些麻烦。

标签: c++ multithreading qt qthread


【解决方案1】:

问题 1 由 Chris 回答。对于问题 2(我第一次没有看到)...

这是设置在单独线程中运行的对象的方法:

// Create the myObject object in its own thread
QThread* myThread= new QThread(); // you can assign `this` as parent if you want...
MyObject* myObject= new MyObject(0); // Assign no parent here (for QObject)
QObject::connect(myThread, &QThread::started, myObject, &MyObject::run, Qt::QueuedConnection);
myObject->moveToThread(myThread);
myThread->start();

你基本上说对了。我认为您缺少启动线程的“myThread->start()”函数。在创建对象时,重要的是要知道任何动态分配都将在父线程空间中创建,因为构造函数在您将其移动到线程之前运行。所以最好在 run() 槽中实例化你需要的任何对象。

启动线程后与对象的任何交互都应通过槽/信号进行。

一旦你启动线程,它就会发出started并且你的run()槽会被调用。

connect 和 moveToThread 的顺序无关紧要,只要你在调用myThread-&gt;start()之前完成所有这些操作

注意

这对于启动线程很有用。有一些规则也可以帮助您干净地终止线程......但这可能会偏离主题

【讨论】:

  • 我在一个单独的函数中启动线程,所以我忘记将它包含在伪代码中。
  • @Amomum 啊,好吧,很公平:) ...那么我认为你应该没有任何问题。你的线程有什么问题?
  • @Amomum 还值得注意的是,您的连接类型(默认为自动)将意味着您的信号是 Qt::QueuedConnection 一旦您将对象移动到不同的线程(而在移动之前它们会是直接连接)...在我的示例中,除非我有理由使用直接连接,否则我更喜欢始终使用排队连接
  • 克里斯,你已经解决了我所有的问题,感谢你:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-01-10
  • 2011-05-08
  • 1970-01-01
  • 1970-01-01
  • 2015-01-31
  • 1970-01-01
相关资源
最近更新 更多