How to pass an object to QThread run method
-
I created a a QList<HGLOBAL> and want to pass that to a background thread. I know I can do this in MOC via a signal. However, that implies an already running QThread doesn't it? The thread has to accept a QList and "run" once. I can pass it via constructor but the thread isn't started yet. Also, can I re-start the thread?
Edit: I guess a better way to express this is how do I share objects between a main (GUI) thread and another thread.
-
Hi,
Do you mean calling start again after you stopped it ? Yes as long as you didn't terminate your thread.
How to pass data, well it depends. Do you need to update it while your thread is running ? Is it a set once then run ?
-
You can QObject::moveToThread an QObject to a non-running thread.
You can connect your object (i.e. wrapper QObject for your QList) to QThread::started to provide any processing of the list.
To access the list (or any data) across threads you can for example make a wrapper QObject for your list (as per above), declare your QList as a member and setter/getter function with QMutex locking/unlocking in them. Accessing the list would be thread safe then.
The wrapper can have any number of signals and slots to notify outside world of stuff or do some processing when itself gets signalled. That all is also thread safe including QObject::connect and QObject::disconnect.
However conceptually I would like to ask, why do you need to have a list in another thread? Unless it is supposed to be connected directly to some heavy processing, it should not really matter where it resides (in which thread). If it needs to be fed to a processing operation, you can pass it there using a signal. Because having it in another thread means retrieving it will cause deep copy rather than just getting a reference. If you would only access its values (or set data) you could provide your wrapper object with interface for that (again, using QMutex). That would decrease the amount of data copying around. But of course if you never access it from outside your background thread and it is only used there then it makes sense.
Best of luck anyway!
-
[quote author="SGaist" date="1414020519"]Hi,
Do you mean calling start again after you stopped it ? Yes as long as you didn't terminate your thread.
How to pass data, well it depends. Do you need to update it while your thread is running ? Is it a set once then run ?[/quote]
By terminate you mean at the completion of the run method? Then yes. The run method runs once then returns. The start() method would be called again.
As far as sharing data, I created a public object in the Worker class and copy the object from the main window class to the worker i.e worker->Object = Object before calling start(). The object in the MainWindow class would get updated, copied then worker->start gets called. I could have passed that to the constructor of the worker but it wouldn't be updated until just before calling start. Passing it via a signal would work either because I wanted to have the shared object passed to the worker when the run method starts.
Hope that's clear.
Thanks
-
[quote author="Resurrection" date="1414060371"]
However conceptually I would like to ask, why do you need to have a list in another thread? Unless it is supposed to be connected directly to some heavy processing,
Best of luck anyway![/quote]
Yes VERY heavy processing which really dragged down painting/updating in the main thread.
-
If the run method exits gracefully then it's not terminated ;)
-
[quote author="SGaist" date="1414105656"]If the run method exits gracefully then it's not terminated ;)[/quote]
It must be because it doesn't throw an exception when I successively call start(). As to the other point, I couldn't determine another way than to have a public member of the worker class and copy a member of the MainWindow class to the Worker class
-
[quote author="astodolski" date="1414111375"]
It must be because it doesn't throw an exception when I successively call start().[/quote]Maybe there is a terminology confusion but see QThread::terminate for details. It does not prevent you from restarting the thread. You should still not use it though and rather use any of quit(), exit(), sleep(), msleep(), wait()...
[quote author="astodolski" date="1414111375"]As to the other point, I couldn't determine another way than to have a public member of the worker class and copy a member of the MainWindow class to the Worker class[/quote]
That's because the only other way would be to use a mutex on your data if it was in another thread (i.e. main GUI thread) when accessing it. Since you quite rightly imho want the data to be where processing is done you need to copy it there either once or use signals to deliver it as many times as needed.
Oh and if you want to access the member outside of the thread where it will be then you should declare it private and make setter & getter methods with mutex (QMutex) to lock it down when it is accessed.
However I am not sure if HGLOBAL can be put in a signal right out of the box (even though it's *void afaik that is listed as known type to Qt meta object system). If not you will have to register it first: http://qt-project.org/doc/qt-5/qmetatype.html#details
-
Indeed, terminated != finished. As an analogy, terminating a thread is like using a bazooka to stop a car. The car will stop indeed but its state will not be the same as when you just brake.
-
[quote author="Resurrection" date="1414129203"][quote author="astodolski" date="1414111375"]
It must be because it doesn't throw an exception when I successively call start().[/quote]Maybe there is a terminology confusion but see QThread::terminate for details. It does not prevent you from restarting the thread. You should still not use it though and rather use any of quit(), exit(), sleep(), msleep(), wait()...
[quote author="astodolski" date="1414111375"]As to the other point, I couldn't determine another way than to have a public member of the worker class and copy a member of the MainWindow class to the Worker class[/quote]
That's because the only other way would be to use a mutex on your data if it was in another thread (i.e. main GUI thread) when accessing it. Since you quite rightly imho want the data to be where processing is done you need to copy it there either once or use signals to deliver it as many times as needed.
Oh and if you want to access the member outside of the thread where it will be then you should declare it private and make setter & getter methods with mutex (QMutex) to lock it down when it is accessed.
However I am not sure if HGLOBAL can be put in a signal right out of the box (even though it's *void afaik that is listed as known type to Qt meta object system). If not you will have to register it first: http://qt-project.org/doc/qt-5/qmetatype.html#details[/quote]
Yes there was a subtle misuse of term on my part. I mean to use the term finished - as in complete - as in run method returns etc. Certainly not brute forced terminate!
The other point as to passing HGLOBAL does in fact work when registered to the MOC which I used.