Pregunta

I have a problem with Qt multithread. I have a class that i want as a thread

//protdata.cpp

class ProtData : public QObject
{
   Q_OBJECT
   private:
      QList<ProtDataInputHandler *> _inputs;
   public:
      ProtData();
      void addInput();
      ....
};

void ProtData::addInput(QIODevice *input, bool network_order)
{
   _inputs.append(new ProtDataInputHandler());
}

I have another class display.cpp where i instantiate the protdata object as a thread using moveToThread();

//display.cpp
...
QThread* newThread = new QThread();
_protdata->moveToThread(newThread);
newThread->start();
...

At some point, in display.cpp:

//display.cpp
....
_protdata->addInput();

When i execute the addInput method, i get the following error:

QObject: Cannot create children for a parent that is in a different thread. (Parent is ProtData(0x19bba50), parent's thread is QThread(0x19b3c18), current thread is QThread(0x1f08930)

What get wrong? I must move also the ProtDataInputHandler class into the newThread? How?

Thanks

¿Fue útil?

Solución

AddInput must be called only in procdata.cpp. You can use a signal to call your function if you define it like a slot :

// display.h

signals :

void addInputSignal();

// display.cpp
QObject::connect(this,  SIGNAL(addInputSignal()), newThread,  SLOT(addInput()));
// ...
emit addInputSignal(); 

// protdata.h

public slots:

void addInput();

Otros consejos

Try marking your function as Q_INVOKABLE:

Q_INVOKABLE void addInput();

Now, you can use QMetaObject::invokeMethod in order to make a cross-thread method call. Moving to the other thread does not affect calls you make directly, but it does effect events and signal calls, such as this:

QMetaObject::invokeMethod(_procdata, "addInput", Qt::AutoConnection);

To pass arguments, you'll need to add additional arguments to QMetaObject::invokeMethod, generally using the Q_ARG macro.

Your issue is this line in the code:

_inputs.append(new ProtDataInputHandler());

_inputs were created in the main thread when your ProtData was intantiated in the main thread.

However, you call addInput() operating on this after the your ProtData QObject subclass was moved into a different thread.

The best solution would be to use the signal-slot mechanism in Qt.

Basically, you would definte a slot in your ProtData class as well as a signal. You would emit the signal from within addInput and your corresponding slot would be queued by the Qt event loop for execution.

You would then establish the connection between the signal and slot in the ProtData constructor.

Putting all this theory into practice, you would modify your code as follows:

//protdata.cpp

class ProtData : public QObject
{
   Q_OBJECT
   private:
      QList<ProtDataInputHandler *> _inputs;
   public:
      explicit ProtData(QObject *parent = 0);
      void addInput();
   public signals:
       void appendInput();
   public slots:
       void handleAppendInput();
      ....
};

ProtData::ProtData(QObject *parent)
    : QObject(parent)
{
    ...
    connect(this, SIGNAL(appendInput()), SLOT(handleAppendInput()));
    ...
}

void ProtData::handleAppendInput()
{
   _inputs.append(new ProtDataInputHandler());
}

void ProtData::addInput(QIODevice *input, bool network_order)
{
    emit appendInput();
}

Note that I also fixed further issues in your code:

  • I made your constructor explicit as it should be due to uniform initialization with C++11 and on.

  • You forgot to have a QObject parent argument that is assigned to the base class, so I amended that, too, while having a default "no parent" value when not specified explicitly.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top