October 11, 2011

vidar vidar
Lab Rat
58 posts

Problem in Multithreading Application

 

Hi,

I have two threads:

  • the main application containing the GUI
  • and a second one that I use to update the values of an array, whenever settings in the GUI change.

To notify the worker thread, I emit a signal that is connected with a slot of the worker’s thread:

  1. connect(this,    SIGNAL (updateArr(QPainterPath)),
  2.       this->threadUpdater,SLOT (updateArr(QPainterPath)), Qt::QueuedConnection);

From the Qt Documentation I expected the slot to be executed in the worker’s thread. I am using Mutexes to ensure, that accessing member values is safe:

  1. void ThreadUpdater::updateArr(const QPainterPath &bezPath) {
  2.  
  3.  mutexUpdate->lock();
  4.  doSomething(bezPath);
  5.  mutexUpdate->unlock();
  6. }

However, when debugging the Application, I get the warning: “A mutex must be unlocked in the same thread that locked it.”).

It seems that, the slot is not called from within the worker’s thread, as I expected… What am I doing wrong?

The worker’s thread does install an event loop:

  1. void ThreadUpdater::run() {
  2.  mutexUpdate = new QMutex();
  3.  exec();
  4.  delete mutexUpdate;
  5. }
  6.  
  7. void ThreadUpdater::stopThread() {
  8.  quit();
  9. }

13 replies

October 11, 2011

Vass Vass
Ant Farmer
706 posts

Please, show, how you create working thread object (ThreadUpdater).

 Signature 


Vasiliy

October 11, 2011

Andre Andre
Robot Herder
6422 posts

Seems like that thread is constructed wrong. Read this article [developer.qt.nokia.com] on the wiki please.

October 11, 2011

Gerolf Gerolf
Hobby Entomologist
3251 posts

vidar wrote:
Hi,
To notify the worker thread, I emit a signal that is connected with a slot of the worker’s thread:

  1. connect(this,    SIGNAL (updateArr(QPainterPath)),
  2.       this->threadUpdater,SLOT (updateArr(QPainterPath)), Qt::QueuedConnection);

From the Qt Documentation I expected the slot to be executed in the worker’s thread. I am using Mutexes to ensure, that accessing member values is safe:

This is only true, if you moved the thread object to be attached to the thread itself. Each QObject has a thread affinity to the thread that created it. The QThread object itself is a QObject that hosts a thread, but its affinity is towards its creator thread. Tho change that, use moveToThread.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

October 11, 2011

Andre Andre
Robot Herder
6422 posts

I don’t think that using moveToThread on the thread object itself is very good advice. Instead, it would be better to start using QThread like this:

  1. MyWorkerObject* worker = new MyWorkerObject();
  2. QThread* workerThread = new QThread(this);
  3. worker->moveToThread(workerThread);
  4. connect(this, SIGNAL(someSignal()), worker, SLOT(someSlot()));
  5. workerThread->start();

That is: use a vanilla QThread (not a subclass), and use a QObject-derived worker object that you move to the worker thread object.

October 11, 2011

vidar vidar
Lab Rat
58 posts

Thank you! I think I still need to meditate about the “the QThread object does not live in the Thread itself” – thing. But from the wiki article I read that it is a good way to connect the signal & slot from within the run() method of the QThread… Or to use the code that Andre posted. I will check it out.
Thanks a lot!

October 12, 2011

Andre Andre
Robot Herder
6422 posts

To help you in your meditation: you should understand that QThread is an object that manages a thread, but it is not the thread itself. A thread is not an object, it is a path of code execution that runs parallel to another code execution path.

October 13, 2011

Gerolf Gerolf
Hobby Entomologist
3251 posts
vidar wrote:
But from the wiki article I read that it is a good way to connect the signal & slot from within the run() method of the QThread…

That would be even better and could remove the moveToThread thing.

  1. Create a subclass of QThread and add some slots
  2. connect the outside class with the slost of your thread object
  3. you QThread should emit a signal for each slot
  4. inside run, create the worker qobjects and connect them to your threads signals.

This decouples the worker objects from the outer world, removes the moveToThread stuff and from outside, it looks (and it also does) that the thread handles the stuff.

This is just another idea how to solve that.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

October 13, 2011

Andre Andre
Robot Herder
6422 posts

In that case, I would remove the QThread itself from view. Don’t subclass it, but instead just subclass a QObject that you give the nessecairy API, and let that class care about what way of making the operations async it wants to use. That could be QThread, it could be not. I would really advice against subclassing QThread and adding slots and/or signals to it.

October 13, 2011

Volker Volker
Ant Farmer
5331 posts

Wasn’t that subclassing QThread exactly that ‘You’re doing it wrong’ [labs.qt.nokia.com] thing?

October 14, 2011

Gerolf Gerolf
Hobby Entomologist
3251 posts

If you move the thread object, YES. But that wasn’t my suggestion. My idea was to use it as multiplexer so you can create the target QObjects inside run and connect the signals there.

 Signature 

Nokia Certified Qt Specialist.
Programming Is Like Sex: One mistake and you have to support it for the rest of your life. (Michael Sinz)

October 14, 2011

Volker Volker
Ant Farmer
5331 posts

In that case, I would recommend creating a plainly QObject derived class that keeps a QThread as member variable (or pointer). This way the implementation details do not leak to the outside, as the users of the class should not be exposed with the QThread methods directly.

October 14, 2011

Andre Andre
Robot Herder
6422 posts

That’s what I suggested as well:

Andre wrote:
In that case, I would remove the QThread itself from view. Don’t subclass it, but instead just subclass a QObject that you give the nessecairy API, and let that class care about what way of making the operations async it wants to use.

Do not subclass just because it is convenient. Subclass because your object is (a specialized version of) the class you are subclassing and you intend to use it that way. In this case, encapsulation seems a much better solution.

October 14, 2011

vidar vidar
Lab Rat
58 posts

Hi,

looking at the philosophy of object-oriented design, Andre’s and Volker’s solution seems to be more “correct”.
However, I somehow prefer the dataflow-oriented solution that Gerolf mentioned (subclassing of QThread and using it as a “proxy”), for the following reason: the overall application is clearly partitioned into “domains” in which things are done in parallel. The borders of these domains are the instances of the QThread subclasses and thus can be identified easily.

 
  ‹‹ Qtextstream and Qfile      How to know the timezone using Qt classes. ››

You must log in to post a reply. Not a member yet? Register here!