Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Passing QList<QString>* to a signal from QThread

In my qt application i have a class (worker) which is called from the object which runs in a thread. In my worker class i create QList, like this

QList <QString> albums;

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

I receive this signal in another class which is wrapping my worker, for thread-usage. Let's call this class GetAlbumsThread. In there i successfully receive SignalGotAlbums in a slot

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

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

In this slot i'am firing another signal gotAlbums which is suppose to be connected with a slot in my gui thread, and pass my QList in there. My problem is, when im trying to pass QList from a thread to gui, it's just not working! Slot not receiving gotAlbums Signal;

Signal is declared like so:

void gotAlbums(QList<QString> &);

And connected to my gui slot (of course in my gui thread) like that:

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 never get's called for some reason. connect returns true. Can someone help me with this. I think the problem is in the passing QList between threads.

like image 314
SirLanceloaaat Avatar asked Feb 17 '23 06:02

SirLanceloaaat


2 Answers

The issue here is that you are using a reference for your signal/slot, i.e. a QList<QString> &. This is not compatible with threads since they use their own private stack, and in this case what you do is passing a pointer to an object in the stack from one thread to another.

Possibilities are:

  1. Use raw QList<QString> signals/slots, that will force a copy.
  2. Allocate the QList<QString> with a new (hence will go in the heap instead of the stack), and use QList<QString> * signals/slots.

The following code illustrates these two methods:

// 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();
}

Output:

1 
2 
3 
4 
5 
6 
7
like image 182
Boris Dalstein Avatar answered Mar 05 '23 17:03

Boris Dalstein


Did you try to register your QList object before calling Object::connect(...) ?

You can declare the meta-type using this code:

qRegisterMetaType< QList<QString> >( "QList<QString>" );
like image 35
Dufeu Avatar answered Mar 05 '23 18:03

Dufeu