从QThread向信号传递QList<QString>*

4

在我的Qt应用程序中,我有一个类(worker),它从运行在线程中的对象中调用。在我的worker类中,我创建了一个QList,如下所示:

QList <QString> albums;

while (i.hasNext())
{
  QRegularExpressionMatch album = i.next();
  albums.append(album.captured("album"));
}
emit SignalGotAlbums(albums);

我在另一个包装了工作线程的类中接收到这个信号,与线程使用有关。我们将其称为 GetAlbumsThread 类。在这个类中,我成功地在一个插槽中接收到 SignalGotAlbums 信号。

void GetAlbumsThread::Reply(QList <QString> &list)
{

 emit gotAlbums(list);
 emit finished();
}

在这个插槽中,我正在触发另一个名为gotAlbums的信号,该信号应该与我的GUI线程中的一个插槽连接,并将我的QList传递到那里。我的问题是,当我试图从线程传递QList到GUI时,它就无法正常工作!插槽没有接收到gotAlbums信号;

信号的声明如下:

void gotAlbums(QList<QString> &);

然后像这样连接到我的GUI插槽(当然在我的GUI线程中):

private slots:
    void AlbumsReceived(QList<QString> &list)
    ...

    QThread* albumsThread = new QThread();

    GetAlbumsThread *albumsObject = new GetAlbumsThread();

    albumsObject->moveToThread(albumsThread);

    connect(albumsThread, SIGNAL(started()), albumsObject, SLOT(process()));

    connect(albumsObject, SIGNAL(gotAlbums(QList<QString> &)), this, SLOT(AlbumsReceived(QList<QString> &));

     albumsThread->start();

出于某种原因,AlbumsReceived从未被调用。connect返回true。有人能帮我解决这个问题吗?我认为问题出在不同线程之间传递QList。


除非我遗漏了什么,否则您正在将 QList 作为堆栈上的局部变量创建,然后在信号中传递对它的引用,这意味着 QList 可能已经超出范围并且在排队的连接返回到 GUI 线程之前已被销毁。这不应该防止槽接收信号,但本质上是一个潜在的恶意 bug。 - Ninjammer
我应该将QList设为全局变量还是使用new创建? - SirLanceloaaat
顺便说一下,我也尝试过通过调用new QList<QString>来将QList放入堆中,但是我得到了“对不完整类型'QStaticAssertFailure<false>'的'sizeof'的无效应用程序”错误。 - SirLanceloaaat
我建议您更改标题,因为这绝对是与使用线程以及通过信号/插槽(QList或其他内容)传递引用相关的问题。修改后可以帮助其他人找到解决方法。 - Boris Dalstein
2个回答

6

在调用Object::connect(...)之前,您是否尝试过注册QList对象?

您可以使用以下代码声明元类型:

qRegisterMetaType< QList<QString> >( "QList<QString>" );

5
这里的问题是您正在使用信号/槽的引用,即QList<QString>&。这与线程不兼容,因为它们使用自己的私有堆栈,在这种情况下,您所做的是将指向堆栈中对象的指针从一个线程传递到另一个线程。
可能的解决方法是:
  1. 使用原始的QList<QString>信号/槽,这将强制进行复制。
  2. 使用new分配QList<QString>(因此将进入堆而不是堆栈),并使用QList<QString> *信号/槽。
以下代码说明了这两种方法:
// A.h

#include <QObject>
#include <QDebug>

class A: public QObject
{
Q_OBJECT

public slots:
    void foo(int i) { qDebug() << i; }
    void bar(QList<int> l) { foreach(int i, l) qDebug() << i; }
    void bar2(QList<int> * l) { foreach(int i, *l) qDebug() << i; }
};


// Worker.h

#include <QObject>

class Worker: public QObject
{
    Q_OBJECT

public slots:
    void process()
{
        // pass an int
        emit foo(1);

        // pass a list by value
        emit bar(QList<int>() << 2 << 3 << 4);

        // pass a poniter to a list
        list = new QList<int>();
        *list << 5 << 6 << 7;
        emit bar2(list);

        emit finished();
    }

signals:
    void finished();
    void foo(int);
    void bar(QList<int>);   
    void bar2(QList<int> *); 

private:
    QList<int> * list;
};


// main.cpp

#include <QApplication>
#include <QThread>
#include <QObject>

#include "A.h"
#include "Worker.h"

int main(int argc, char** argv)
{
    QApplication app(argc, argv);

    A * a = new A();
    Worker * worker = new Worker();
    QObject::connect(worker, SIGNAL(foo(int)), a, SLOT(foo(int)));
    QObject::connect(worker, SIGNAL(bar(QList<int>)), a, SLOT(bar(QList<int>)));
    QObject::connect(worker, SIGNAL(bar2(QList<int>*)), a, SLOT(bar2(QList<int>*)));

    QThread * thread = new QThread();
    worker->moveToThread(thread);

    QObject::connect(thread, SIGNAL(started()), worker, SLOT(process()));
    QObject::connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
    QObject::connect(thread, SIGNAL(finished()), &app, SLOT(quit()));
    thread->start();

    return app.exec();
}

输出:

1 
2 
3 
4 
5 
6 
7

尝试了p2。我在使用堆QList分配时遇到了一个错误:“对不完整类型'QStaticAssertFailure<false>'的'sizeof'的无效应用”。 - SirLanceloaaat
@SirLanceloaaat 您是否改用 QList<QString> * 而不是 QList<QString> 来更改信号和槽的定义?请参考我的编辑获取完整的工作示例。 - Boris Dalstein
是的,我确实更改了信号槽定义,但仍然收到了QStaticAssertFailure错误(需要元类型定义blabla)。所以我只是更改了定义并将QList<QString>更改为QStringList,现在它可以正常工作了。感谢您的帮助。 - SirLanceloaaat
@SirLanceloaaat:这很奇怪。在检查后,QStringList并不像我以前认为的那样是一个裸的typedef QList<QString>,而是继承自它,这可能解释了不同的行为方式。但是你尝试过我的代码吗?因为我使用了从堆中传递的对象,使用了QList<QString>*,并且它运行得很好,而如果我使用从堆栈中传递的对象,使用了QList<QString>&,我会得到和你一样的错误。所以要么你的代码有其他问题,要么你的配置有问题。(或者我的配置比它应该的更宽松) - Boris Dalstein
是的,我尝试了你写的所有内容,我将所有信号槽委托更改为QList<QString> *。也许我错过了一些包含文件。 - SirLanceloaaat
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接