Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Creating QThread from another QThread



  • I'm creating an application that perform a long task and after condition should spawn a second thread to do some computation.

    class Buffer : public QObject
    {
        Q_OBJECT
    public:
        Buffer(QObject* parent = 0);
    private:
        
    public slots:
        void readData();
        void saveData();
    
    };
    

    The readData method has an infinity loop inside and so I decided to move the Buffer object to a Qthread in the main.

    Buffer buffer;
    QThread *readThread = new QThread;
    readThread->setObjectName("customThread");
    readThread->setParent(&buffer);
    buffer.moveToThread(readThread);
    QObject::connect(readThread,SIGNAL(started()),&buffer,SLOT(readData()));
    QObject::connect(readThread,SIGNAL(finished()),thread,SLOT(deleteLater()));
    readThread->start();
    

    On some condition, checked in readData() method, I should call saveData() in another thread because the computation must be done concurrently with readData(). I tried this:

    
    QThread* thread = new QThread(QThread::currentThread()->parent());
    moveToThread(thread);
    connect(thread,SIGNAL(started()),QThread::currentThread()->parent(),SLOT(saveData()));
    connect(thread,SIGNAL(finished()),thread,SLOT(deleteLater()));
    thread->start();
    

    The first time that condition occurs, everything works fine. The second one, I get:

    QObject::moveToThread: Current thread (0xd29078) is not the object's thread (0x6e000df0).
    Cannot move to target thread (0x6e002c68)
    

    Probably because I change the affinity of readThread and I cannot call moveToThread again.
    Is there a way to solve this problem? Or is there a particular pattern that I should implement for this case?


  • Moderators

    @Crindu said in Creating QThread from another QThread:

    Probably because I change the affinity of readThread and I cannot call moveToThread again.
    Is there a way to solve this problem? Or is there a particular pattern that I should implement for this case?

    Move the creation of the new thread back to parent of your buffer thread. Should work, although it will introduce a small delay (buffer thread will need to send info to it's parent via signal, and then parent thread will start creating the new thread).



  • @Crindu said in Creating QThread from another QThread:

    Buffer buffer;

    Lifecycle is a race condition. If you create buffer on the stack, when the main thread will unwind that stack it will deallocate the memory of the object while another thread is working on it = race condition.

    QThread *readThread = new QThread; memory leak. you never stop the thread so readThread,SIGNAL(finished()) will never fire and the object will not be deleted. same thing in QThread* thread = new QThread(QThread::currentThread()->parent()); as, in your example, QThread::currentThread()->parent() is null

    TBH, I think you are going overkill with this. As long as you can keep buffer alive until all the threads finish you can easily use QtConcurrent::run to execute the two methods. Make sure there's no internal race condition between readData and saveData (the names would suggest there is so you'd need to manage it with mutexes/semaphores/read-write locks)



  • @VRonin readThread has buffer as his parent:

    readThread->setParent(&buffer);
    

    Am I wrong?
    Yes the two methods have a lot of synchronization, I already managed it.
    Finally I tried this and seems to work.

    Buffer* buffer = (Buffer*)(QThread::currentThread()->parent());
    QtConcurrent::run(buffer, &Buffer::saveData);
    

    Do you think I should allocate Buffer on the heap, instead?



  • @sierdzio I already tried, it's strange because saveData is called but the error remains.



  • @Crindu said in Creating QThread from another QThread:

    Finally I tried this and seems to work.

    You don't need QThread at all, you can just use QtConcurrent::run(&buffer, &Buffer::readData);.

    @Crindu said in Creating QThread from another QThread:

    readThread has buffer as his parent:
    readThread->setParent(&buffer);

    Am I wrong?

    Yes, QThread is not the thread, it's a wrapper around it, if you destroy QThread when the thread is running you will see a critical error in the debug output



  • @VRonin
    The second thread should start inside readData method, during the execution of the first thread.
    If I use QtConcurrent::run(&buffer, &Buffer::readData); , how can I retrieve the pointer to Buffer in order to create the second thread for saveData?



  • @Crindu said in Creating QThread from another QThread:

    If I use QtConcurrent::run(&buffer, &Buffer::readData); , how can I retrieve the pointer to Buffer in order to create the second thread for saveData?

    readData is a method of Buffer so you can very easily use this: QtConcurrent::run(this, &Buffer::saveData);



  • @VRonin
    Thank you, it works perfectly. I thought that ‘this’ could not be called inside a thread.


Log in to reply