[solved]A problem in using QThread



  • I meet an issue "QObject: Cannot create children for a parent that is in a different thread.
    (Parent is QNativeSocketEngine(0x9d85728), parent's thread is QThread(0x9aa77f8), current thread is Downloader(0x9de8700)"
    I write a class called "Downloader", and I wanna it runs in another thread than main thread. Downloader inherit
    from QThread. I overload run() as:
    @
    void Downloader::run(){
    mutex.lock();
    QString file_path = filename;
    QFile file(file_path);
    int i=1;
    int index = file_path.lastIndexOf('.');
    while(file.exists()){
    file_path = file_path.replace(index, 1, QString("(%1).").arg(QString::number(i)));
    file.setFileName(file_path);
    i++;
    }
    if(file.open(QIODevice::WriteOnly)){
    mutex.unlock();
    qint64 msize = 0;
    while(msize<filesize){
    if(socket.waitForReadyRead()){
    QByteArray x=socket.read();
    int len=file.write(x);
    msize += x.count();
    }
    }
    socket.close();
    file.close();
    }
    else{
    mutex.unlock();
    }
    }
    @
    In main thread, I call "Downloader *downloader = new Downloader(); downloader->run(); ",then it report the issue. I want to know what's wrong in my code.
    Thx.

    By the way, Another class called "Uploader" is similar, but It runs normal.
    @
    void Uploader::run(){
    qint64 size=0;
    file->open(QIODevice::ReadOnly);
    while(size < file->size()){
    QByteArray x= file->read(1024);
    size += x.count();
    socket.write(x);
    }
    socket.close();
    file->close();
    }
    @

    I learnt that there are two ways using multithread, inherit QThread or use movetothread then emit a signal to call a slot function in another thread. I try to avoid too many connections between signals and slots, so I choose to inherit QThread.
    But what's wrong if the "socket" is created in main thread. In fact, "socket" is Downloader's member, and it connect to host in constructor.
    @
    Downloader::Downloader(const QString& filename,
    const QString& address,int port,qint64 size, QObject *parent) :
    QThread(parent)
    {
    this->filename = filename;
    this->filesize = size;
    this->socket.connectToHost(address,port);
    }
    @
    Or should I must go in "movetothread" way?
    (My mutex in Downloader is used to mutex file access on the disk, and unlock in file.open() is to make sure the file's been created. )


  • Moderators

    It is recommended not to subclass QThread if it can be avoided (which is in most cases). It is easy to confuse QThread (which is running in the main thread) with the thread (code inside run()).

    The snippet does not show what is "socket" variable. It also does not use "len" variable. You unlock the mutex in both results of "if" - why? You can do it once, before the if. Or use a QMutexLocker. Also, there seems to be no reason to use QMutex in this code at all - you lock it only to modify a couple of local variables, nothing that is shared between threads. So there is no danger of locking here (although I think you are doing this to avoid ceating duplicate files, in such case it may be a good thing indeed).

    You can use QFileInfo instead of QFile. And there is no reason to construct the object, you can use the static QFileInfo::exists() method.

    Now, on to what I suspect: your socket lives in a different thread from run().


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    You seem to be using a socket that's been created e.g. in the your Uploader/Downloader contractor. Which means that this socket has thread affinity with the that created your object not the thread that is running run. QThread is not a thread per se but a thread manager.

    Please have a look at QThread's latest "documentation":http://qt-project.org/doc/qt-5/qthread.html so see the various use and technique.



  • Thanks for your help, the issue had been solved.
    It's like that QTcpSocket couldn't read and create in different Thread, but write could. It may be a mechanism of OS. So I created QTcpsocket and call its read method in the new thread instead.
    @
    if(file.open(QIODevice::WriteOnly)){
    mutex.unlock();
    socket = new QTcpSocket();
    socket->connectToHost(address, port);
    qint64 msize = 0;
    while(msize<filesize){
    if(socket->waitForReadyRead()){
    QByteArray x=socket->read(1024);
    int len=file.write(x);
    msize += x.count();
    }
    }
    socket->close();
    file.close();
    delete socket;
    }
    @


  • Lifetime Qt Champion

    You're welcome !

    Now that you have your thread running, please update the thread title prepending [solved] so other forum users may know a solution has been found :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.