Checking the status of a python thread from a seperate function - python

Currently I am able to run a thread and update label items in a GUI (pyqt5) as the thread is running. However, I want to add information on the status of the thread, i.e. when the thread starts (label updated as :'thread initiated') and when the thread ends (label updated as: 'thread complete'). The thread start update is not a problem because I can update the label as soon as the thread is initiated. However, the thread end update is somewhat more problematic since I have no way of knowing when the thread has finished. I have tried thread.join(), though this prevents dynamic update of labels when the thread is running (The GUI freezes until the thread has finished). I have tried to update the label from a separate function but with no success.
My current code (shortened):
def onbuttonpress(self):
self.label.setText('thread initiated')
self.simulation()
self.label.setText('thread finished')
def simulation(self):
def sim():
pythoncom.CoInitialize()
------code-----
self.thread = threading.Thread(target=mt)
self.thread.start()
Is there a alternative to thread.join() that works without crashing GUIs?

You can use the timeout parameter of join() to try joining, if unsuccessful, it's not ready yet.
https://docs.python.org/2/library/threading.html#threading.Thread.join
For the duration of the timeout, the GUI thread will be blocked, so set it to a small value (e.g. 1 ms). Do this check periodically (e.g. once every second) until the thread is done.
Alternatively, use the signal-slot mechanism of Qt to notify the GUI thread from the worker thread.
pyqt4 emiting signals in threads to slots in main thread
PyQt5 - How to emit signal from worker tread to call event by GUI thread

Related

Pausing the Main Thread in Python

I currently have a main function being run in Python on the main thread. This main function creates an additional thread called ArtificialPlayerControllerSynthesis to run a background process. I would like to pause the main thread for a second or two to allow the background process to finish before continuing in the main thread. However, all solutions to this issue that I can find, such as from Pausing a thread using threading class, require passing an event object as an argument to the thread I want to pause. This is not possible in my case, or would at the very least require restructuring my code and moving my main function to a new thread. Is it possible to simply pause the main thread? I am new to Python and threading, thanks in advance for yall's help.
thread = threading.Thread(target=some_func)
thread.start()
do_some_stuff_now()
thread.join() # blocks until thread finishes
do_some_stuff_later()

Restart QThread with GUI

I am using QThread to do some calculations in a separate Thread.
The Thread gets started by a button click, witch launches the function StartMeasurement().
The Thread can finish the process by itself (after finished the calculations)
and emits the PyQT Signal finished. Or the thread can be stopped by the User by the stopBtn click.
The terminate() function is working, but I get a lot of troubles when I try to start the thread again.
Is it recommendable to use the movetoThread() approach here?
Or how could I ensure that the thread is stopped correctly to enable a proper restart. (means, starting new!)
# starts the measurment in a Thread: StartMeasurement()
def StartMeasurement(self):
self.thread = measure.CMeasurementThread(self.osziObj, self.genObj, self.measSetup)
self.thread.newSample.connect(self.plotNewSample)
self.thread.finished.connect(self.Done)
self.stopBtn.clicked.connect(self.thread.terminate)
self.stopBtn.clicked.connect(self.Stop)
self.thread.start()
It's not a problem. The general practice when working with QThread is to connect its finished() signal to the deleteLater() slot of the objects that have been moved to the separate thread via moveToThread(). It's done in order to properly manage the memory when you then destroy your thread because it's assumed that you will first quit the thread and then destroy its instance. ;) This should tell you that stopping a thread has nothing to do with the destruction of those objects UNLESS you have established the connection I've described above.
It is perfectly fine to restart a thread IF you have stopped it properly using quit() and wait() to actually wait untill the stopping is completed.
However my advice is to not do that unless that extra thread has a huge impact on your application for some reason (highly unlikely with modern machines).
Instead of restarting the thread consider the following options:
implement a pause flag that just makes the thread run without doing anything if it's set to true (I've used this example of mine many times to demonstrate such behaviour (check the worker.cpp and the doWork() function in particular) - it's in C++ but it can be ported to PyQt in no time)
use QRunnable - its designed to run something and then (unless autoDelete is set to true) return to the thread pool. It's really nice if you have tasks that occur every once in a while and you don't need a constatly running separate thread. If you want to use signals and slots (to get the result of the calculation done inside the QRunnable::run() you will have to first inherit from QObject and then from QRunnable
Use futures (check the Qt Concurrent module)
I suggest that you first read the Example use cases for the various threading technologies Qt provides.

PyQt and Threads: Multithreading inquiry

The Situation
I am using python 2.7. I am working on an application that has a GUI utilizing PyQt4.
I have a button in a widget and when you click it it will request a range of IDs specified by the user. The user can specify how many threads the program should allocate for the "job".
My Original Idea
The button spawns a job thread and passes it the range of IDs and the thread count. The job thread then can create child threads and pass them IDs from the range as necessary.
When all the IDs have been fetched the job thread can stop all its worker threads and then stop itself.
I would utilize signals / slots to update GUI elements with data as it is fetched by the worker threads within the job.
I am using threads so the GUI remains interact-able during the fetching process.
The Problem
The "Dreaded PyQt Multi-threading Issue" occurred when I tried to spawn a thread from within a thread.
QObject: Cannot create children for a parent that is in a different thread.
My Workaround
I simply spawned the job thread and the worker threads from the widget that contains the button so no thread is spawned from within a thread, and then "connected" the worker threads to the job thread.
A la aThread = ScrapeThread(self, aJob) where aJob is the master Job thread.
This seems to work, but feels like a workaround more than the proper way to do this.
The Question
What I did seems like a workaround rather than the proper way to multi-thread in PyQt.
Any recommendations?

Do a callback from subclassed thread in main thread

I have a class that inherits from threading.Thread.
After processing an item from a queue I want it to call a function that I handed over to the thread when starting it. Doing that callback from the run-Method will have it run in my worker thread. Is there a way to run that callback inside the MainThread?
Thanks & Greetings,
Sean
You didnt mention intially that you are using pyqt. Qt has signals and slots built in just for this purpose. If you are launching your thread using QThread then it has the 'finished' signal that your main thread can be connected to on a slot. If you need even more control of the resulting signal you can emit a custom one from the thread with any value you want. When you construct the thread just connect its signal to the slot that you want to act as the callback.
Otherwise you would be blocking your main event loop if you are specifically waiting on the thread.
Here is a link specifically about the new style signal/slots: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/new_style_signals_slots.html
It makes it extremely easy now to create a python signal with whatever signature you want and connect it in an object oriented fashion to a slot.
Also as a side note about PyQt... Some of the other answers here have suggested creating a loop on your main thread that waits to collect responses in a queue from its dispatched threads. That is essentially what PyQt does. When you start your app the main thread goes into an event loop. This event loop is processing events that stack up in its event queue. There are different types of signal/slot connections. If your two endpoints are in the same thread, then a direct connection will be made and the emitting signal will call the slot. If they are in different threads, then I believe it goes through the event loop so that it can be processed outside of the emitters thread.
Push the method onto a queue and have the main thread sit and wait on that queue, running each method as it pulls them off.
You can use condition variables and have your main thread wait on a message from the sub-thread. The sub-thread can signal the main thread to call that method.

Parent Thread exiting before Child Threads [python]

I'm using Python in a webapp (CGI for testing, FastCGI for production) that needs to send an occasional email (when a user registers or something else important happens). Since communicating with an SMTP server takes a long time, I'd like to spawn a thread for the mail function so that the rest of the app can finish up the request without waiting for the email to finish sending.
I tried using thread.start_new(func, (args)), but the Parent return's and exits before the sending is complete, thereby killing the sending process before it does anything useful. Is there anyway to keep the process alive long enough for the child process to finish?
Take a look at the thread.join() method. Basically it will block your calling thread until the child thread has returned (thus preventing it from exiting before it should).
Update:
To avoid making your main thread unresponsive to new requests you can use a while loop.
while threading.active_count() > 0:
# ... look for new requests to handle ...
time.sleep(0.1)
# or try joining your threads with a timeout
#for thread in my_threads:
# thread.join(0.1)
Update 2:
It also looks like thread.start_new(func, args) is obsolete. It was updated to thread.start_new_thread(function, args[, kwargs]) You can also create threads with the higher level threading package (this is the package that allows you to get the active_count() in the previous code block):
import threading
my_thread = threading.Thread(target=func, args=(), kwargs={})
my_thread.daemon = True
my_thread.start()
You might want to use threading.enumerate, if you have multiple workers and want to see which one(s) are still running.
Other alternatives include using threading.Event---the main thread sets the event to True and starts the worker thread off. The worker thread unsets the event when if finishes work, and the main check whether the event is set/unset to figure out if it can exit.

Categories