Python&PyGTK: Transport data to threading - python

I would like to transfer data to threading class, but I can't get what is wrong. The code below is from this question and I changed it a little.
This is a code:
import gtk, gobject, threading, time
gobject.threads_init()
class T(threading.Thread):
pause = threading.Event()
stop = False
def start(self, data, *args):
super(T, self).start()
def run(self, data):
while not self.stop:
self.pause.wait()
gobject.idle_add(lambda *a : self.rungui(data))
time.sleep(0.1)
def rungui(self, data):
print "printed"
print data
thread = T()
class Start:
def toggle_thread(self, data=None, *args):
if not thread.is_alive():
thread.start(data)
thread.pause.set()
self.button.set_label('Pause Thread')
return
if thread.pause.is_set():
thread.pause.clear()
self.button.set_label('Resume Thread')
else:
thread.pause.set()
self.button.set_label('Pause Thread')
def __init__(self):
thread = T()
window = gtk.Window()
self.button = gtk.ToggleButton('Start Thread')
data = 3
self.button.connect('toggled', lambda *a : self.start(data), None)
window.add(self.button)
self.button.show()
window.show()
def start(self, data=None):
self.toggle_thread(data)
def main(self):
gtk.main()
if __name__ == "__main__":
start = Start()
start.main()
What do I have to correct to get threading fully working?

Don`t work with gtk out of gui thread. That about:
gobject.idle_add(self.rungui)
Example at your link work fine, but need system kill command for termination.
And super() can`t bring arguments to run() function.
My threads initialization looks like this:
class VirtService(threading.Thread):
def __init__(self, queue):
threading.Thread.__init__(self)
self.queue = queue
def thread_loop(self):
while self.queue.qsize():
data_command = self.queue_get()
...
queue = Queue()
if __name__ == '__main__':
gobject.threads_init()
vs = VirtService(queue)
And you may use Queue for data translation to both directions. You may use also queue for command. In non-graphical thread create c++ poll() analog through Queue.qet(), and in gui thread queue.put()

Related

Pausing a Thread When GPIO Input Interrupt Triggers using Event.set() Inside a Thread Class Method

Good day everyone, Im trying to call a method inside a thread class which should set an event flag inside that thread, resulting in the thread to stop running while the event is set. The current code kind of works, and calls the function, but the event flag does not seem to trigger inside the thread.
The thread is responsible for an operation to run when a button is pressed on the GUI, but it shouldn't run if the event is set.
A minimal version of my code:
import threading
import time
GPIO.setup(18, GPIO.IN, pull_up_down=GPIO.PUD.UP)
global run = 0
class Pump_Thread(threading.Thread):
def __init__(self, interval=0.5):
super(Pump_Thread, self).__init__()
self._stop_event = threading.Event()
self.interval = interval
Pump_threads = threading.Thread(target=self.run, daemon=True)
Pump_threads.start()
def stop(self):
self._stop_event.set()
print("Things have stopped yo...")
def resume(self):
self._stop_event.clear()
print("And Now Things will resume")
def run(self)
while not self._stop_event.is_set():
if (run == 1):
#doing some stuff when bit set#
print("Yeah Yeah, I'm running")
class Page1(Page):
def __init__(self, *args, **kwargs):
#Some Initializing methods to load buttons and graphics
self.start_btn=tk.Button(self,height=32,width =80,command=self.Start)
self.start_btn.place(x=50, y=50)
self.reset_btn=tk.Button(self,height=32,width =80,command=self.Reset)
self.reset_btn.place(x=50, y=80)
def Start(self):
global run
run = 1 #<------Set Bit for code to run
def Reset(self):
d = Pump_Thread()
d.resume() #<-----Run Method inside thread
class Monitor_Thread(threading.Thread):
def __init__(self, interval=0.5):
self.interval = interval
Monitor_Threads = threading.Thread(target=self.Monitor_Thread, daemon=True)
Monitor_Threads.start()
def run(self)
while True:
if Condition == True:
d = Pump_Thread()
d.stop() #<-----Run Method inside thread
class Interrupt_Class(page):
def Input(self):
d = Pump_Thread()
d.stop() #<-----Run Method inside thread
GPIO.add_event_detect(18, GPIO.FALLING, callback=Input, bouncetime=300)
class MainView(tk.Frame):
def __init__(self, *args, **kwargs):
tk.Frame.__init__(self, *args, *kwargs)
super().__init__()
p1 = Page1(self) #Other Pages Added here with navigation buttons to raise the page to the front of the GUI#
p1.show()
if __name__ == "__main__":
root = tk.TK()
main = MainView(root)
main.pack(side="top", fill="both", expand=True)
root.wm_geometry("400x400")
root.attributes("-fullscreen", False)
Thread1 = Pump_Thread()
Thread2 = Monitor_Thread()
root.mainloop()
When the interrupt is triggered, "Things have stopped yo..." is printed, so the method is called, but the process still starts when the GUI Button pressed, meaning the event didn't set. What would be the reason for this?
You seem to have many mistakes piled on top of one another.
You need to look at the many examples on stackoverflow of how to create and manage threads.
You might try something like this:
class Pump_Thread(threading.Thread):
def __init__(self, interval=0.5):
super().__init__()
self._stop_event = threading.Event()
self.interval = interval
def stop(self):
self._stop_event.set()
print("Things have stopped yo...")
def resume(self):
self._stop_event.clear()
print("And Now Things will resume")
def run(self)
while not self._stop_event.is_set():
print("Yeah Yeah, I'm running")
# other parts elided
if __name__ == "__main__":
root = tk.TK()
main = MainView(root)
Thread1 = Pump_Thread()
Thread1.start()
but now all other places which need to start and stop Pump_Thread need access to Thread1. So you should pass this into objects that are created.
class Interrupt_Class(page):
def __init__(self, pump):
self.pump = pump
def Input(self):
self.pump.stop() #<-----Run Method inside thread
ic = Interrupt_Class(Thread1)
You are calling:
d = Pump_Thread()
each time before calling: d.stop() which only makes that thread stop.
How is Pump_Thread instantiated and where do you store the reference to it?
In fact, you don't show how any of your classes are instantiated.

PySide Signals not being sent to Slot, from QThread object

I'm working with a multi-threading application, where a worker thread gets created, that emits a signal.
After creating the thread, I connect the signal with an object slot, that will perform some action.
The problem, is the object slot, is not called, can someone help to figure out what's wrong with this code ?
import time
from PySide import QtCore
from PySide.QtCore import Slot, Signal
class Worker1(QtCore.QThread):
task_done_signal = Signal(int)
def __init__(self):
super(Worker1, self).__init__()
self._run = False
def run(self):
self._loop()
def _loop(self):
count = 0
while self._run:
print("running")
count += 1
self.task_done_signal.emit(count)
def start(self):
self._run = True
super(Worker1, self).start()
def stop(self):
self._run = False
class Worker1Listener(QtCore.QObject):
def __init__(self):
super(Worker1Listener, self).__init__()
#Slot()
def print_task(self, val):
print("listener: {}".format(val))
def test_signals_and_threads():
# create the thread
worker = Worker1()
# create the listener
listener = Worker1Listener()
# connect the thread signal with the slot
worker.task_done_signal.connect(listener.print_task)
worker.start()
time.sleep(5)
worker.stop()
time.sleep(5)
if __name__ == '__main__':
test_signals_and_threads()
Your code has several errors:
You must have an event loop so that Qt handles communications between the various objects of the application, in your case you must use QCoreApplication.
The decorator Slot must have as parameter the type of data of the arguments of the function, in your case: Slot(int)
You should not use time.sleep since it is blocking and does not let the event loop do its work, a possible solution is to use QEventLoop next to a QTimer.
It is always advisable to give a short time for communications to be given, for this we use QThread.msleep.
When you connect between signals that are in different threads, the correct option is to use the Qt.QueuedConnection option.
import sys
from PySide import QtCore
class Worker1(QtCore.QThread):
task_done_signal = QtCore.Signal(int)
def __init__(self):
super(Worker1, self).__init__()
self._run = False
def run(self):
self._loop()
def _loop(self):
count = 0
while self._run:
print("running")
count += 1
self.task_done_signal.emit(count)
QtCore.QThread.msleep(1)
def start(self):
self._run = True
super(Worker1, self).start()
def stop(self):
self._run = False
class Worker1Listener(QtCore.QObject):
#QtCore.Slot(int)
def print_task(self, val):
print("listener: {}".format(val))
def test_signals_and_threads():
app = QtCore.QCoreApplication(sys.argv)
# create the thread
worker = Worker1()
# create the listener
listener = Worker1Listener()
# connect the thread signal with the slot
worker.task_done_signal.connect(listener.print_task, QtCore.Qt.QueuedConnection)
worker.start()
loop = QtCore.QEventLoop()
QtCore.QTimer.singleShot(5000, loop.quit)
loop.exec_()
worker.stop()
loop = QtCore.QEventLoop()
QtCore.QTimer.singleShot(5000, loop.quit)
loop.exec_()
#sys.exit(app.exec_())
if __name__ == '__main__':
test_signals_and_threads()

'QThread: Destroyed while thread is still running' on quit

I'm trying to find a way to quit my app properly. When I exit, I get an error saying QThread: Destroyed while thread is still running. I have a thread for feeding output to a QTextBrowser. What should be the proper way to exit? Here's what I've got:
class LogReceiver(QtCore.QObject):
mysignal = QtCore.Signal(str)
def __init__(self, queue, *args, **kwargs):
QtCore.QObject.__init__(self, *args, **kwargs)
self.queue = queue
def run(self):
while True:
text = self.queue.get()
self.mysignal.emit(text)
if __name__ == '__main__':
queue = Queue()
thread = QtCore.QThread()
my_receiver = MyReceiver(queue)
app = QApplication(sys.argv)
window = MainWindow()
window.show()
my_receiver.mysignal.connect(window.append_text)
my_receiver.moveToThread(thread)
thread.started.connect(my_receiver.run)
thread.start()
sys.exit(app.exec_())
Should thread somehow be terminated upon exit? Note that self.queue.get() blocks and waits for text.
Thanks
You need to re-structure the while loop so that it doesn't block uncondtionally.
You can do this with a simple flag and a timeout:
def run(self):
self.active = True
while self.active:
try:
text = self.queue.get(timeout=1.0)
self.mysignal.emit(text)
except Empty:
continue
So now the queue won't block indefinitely, and the flag will be checked once a second to see if the loop should be exited.
EDIT:
Here's a working example based on your code:
import sys
from queue import Queue, Empty
from PySide import QtCore, QtGui
class LogReceiver(QtCore.QObject):
mysignal = QtCore.Signal(str)
def __init__(self, queue, *args, **kwargs):
QtCore.QObject.__init__(self, *args, **kwargs)
self.queue = queue
def run(self):
self.active = True
while self.active:
try:
text = self.queue.get(timeout=1.0)
self.mysignal.emit('text')
except Empty:
continue
print('finished')
class MainWindow(QtGui.QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
self.queue = Queue()
self.thread = QtCore.QThread(self)
self.receiver = LogReceiver(self.queue)
self.receiver.moveToThread(self.thread)
self.thread.started.connect(self.receiver.run)
self.thread.start()
def closeEvent(self, event):
print('close')
self.receiver.active = False
self.thread.quit()
self.thread.wait()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = MainWindow()
window.show()
sys.exit(app.exec_())
Try:
# previous code here
thread.start()
app.exec_()
thread.terminate()
thread.wait()
sys.exit(0)
Basically when exec_() finishes (QApplication is closed ex. by closing the window) you force the thread to terminate and wait() for it to cleanup. If your thread has an event loop you can call quit() instead of terminate(). terminate() is generally not a good idea see: here.
The more desirable approach would be to put a flag in run() method ex.
while !flag:
do stuff
and change main to:
app.exec_()
flag = True
thread.wait()
sys.exit(0)
Where flag is a global variable. QThread terminates itself when run() method finishes.

Concurrent to QLabel in PyQt

I have i python application, which uses PyQt GUI. It application has some I/O operations, which i want to run in separate threads.
When each thread started, it should write messages to applications main window status bar and when last thread is completed, status bar messages should be cleared.
How can i handle number of threads via QThread?
Here is example of code:
import sys, time
from PyQt4 import QtCore, QtGui
from functools import partial
def io_emulator(sleep_seconds):
print 'We will sleep for %s seconds' % str(sleep_seconds)
time.sleep(sleep_seconds)
class IOThread(QtCore.QThread):
def __init__(self, func):
QtCore.QThread.__init__(self)
self.io_func = func
def run(self):
self.io_func()
class m_Window(QtGui.QWidget):
def __init__(self):
super(m_Window, self).__init__()
self.initUI()
def initUI(self):
self.thread_button = QtGui.QPushButton("Thread", self)
self.thread_button.move(30, 10)
self.spinbox = QtGui.QSpinBox(self)
self.spinbox.move(30, 50)
self.stat_label = QtGui.QLabel("", self)
self.stat_label.setGeometry(QtCore.QRect(200, 200, 150, 14))
self.stat_label.move(30,90)
self.setWindowTitle('Threads')
self.show()
self.thread_button.clicked.connect(self._sleeper)
def _sleeper(self):
seconds = int(self.spinbox.text())
stat_str = 'Sleeping %s seconds' % str(seconds)
io_func = partial(io_emulator, seconds)
set_status_f = partial(self.set_status_msg, stat_str)
self.thread = IOThread(io_func)
self.thread.started.connect(set_status_f)
self.thread.finished.connect(self.clear_status_msg)
self.thread.start()
def set_status_msg(self, msg):
self.stat_label.setText(msg)
def clear_status_msg(self):
self.stat_label.clear()
def main():
app = QtGui.QApplication(sys.argv)
m = m_Window()
sys.exit(app.exec_())
if __name__ == '__main__':
main()
I want, that message is being cleared only when last thread is ended.
You cannot call QWidget functions from any thread but the main thread. If you want another thread to trigger GUI operations, then they should be communicated by emitting signals that are connected to your main thread:
def someFunc():
return "message"
class IOThread(QtCore.QThread):
statusUpdate = QtCore.pyqtSignal(str)
def __init__(self, func):
QtCore.QThread.__init__(self)
self.io_func = func
def run(self):
msg = self.io_func()
self.statusUpdate.emit(msg)
Then in your main thread, connect the io thread to the status label or some intermediate handler:
io_thread = IOThread(someFunc)
io_thread.statusUpdate.connect(self.status_label.setText)
This will create a queued connection, which places the call into the event loop of the main thread for execution.

How to get QThreads to work in a console PySide program?

I'm trying to learn how to use threading in a python program. I'm using PySide and QThreads since I'm going to implement gui afterwards with PySide.
I have understood the main consept of threading, at least I think. But I'm still confused with event loops. And I think that is the problem with my aplication.
Here is a sample application that I can't get to work properly.
In my main class I have several worker threads and I want to them to report their progress to the main main class. But the main program don't print progress messages in real time.
How could I get this to work?
from PySide import QtCore
import time, sys
class MyWorkerThread(QtCore.QThread):
message = QtCore.Signal(str)
def __init__(self, id, parent=None):
super(MyWorkerThread, self).__init__(parent)
self.id = id
def run(self):
for i in range(10):
self.message.emit("%d: %d" % (self.id, i))
time.sleep(0.2)
class MainProgram():
def __init__(self, parent=None):
self.threads = []
self.addWorker(MyWorkerThread(1))
self.addWorker(MyWorkerThread(2))
def addWorker(self, worker):
worker.message.connect(self.printMessage, QtCore.Qt.QueuedConnection)
self.threads.append(worker)
def startWorkers(self):
for worker in self.threads:
worker.start()
worker.wait()
self.workersFinished()
def workersFinished(self):
QtCore.QCoreApplication.instance().quit()
#QtCore.Slot(str)
def printMessage(self, text):
sys.stdout.write(text+'\n')
sys.stdout.flush()
if __name__ == '__main__':
app = QtCore.QCoreApplication(sys.argv)
m = MainProgram()
m.startWorkers()
sys.exit(app.exec_())
worker.wait() is the problem. This call blocks the main thread (in this case the one running event loop) until the worker finishes its job.
Here is a slightly changed version (I've commented my changes):
from PySide import QtCore
import time, sys
class MyWorkerThread(QtCore.QThread):
message = QtCore.Signal(str)
def __init__(self, id, parent=None):
super(MyWorkerThread, self).__init__(parent)
self.id = id
def run(self):
for i in range(10):
self.message.emit("%d: %d" % (self.id, i))
time.sleep(0.2)
class MainProgram():
def __init__(self, parent=None):
self.threads = []
self.addWorker(MyWorkerThread(1))
self.addWorker(MyWorkerThread(2))
def addWorker(self, worker):
worker.message.connect(self.printMessage, QtCore.Qt.QueuedConnection)
# connect the finished signal to method so that we are notified
worker.finished.connect(self.workersFinished)
self.threads.append(worker)
def startWorkers(self):
for worker in self.threads:
worker.start()
# no wait, no finished. you start the threads and leave.
def workersFinished(self):
if all(worker.isFinished() for worker in self.threads):
# wait until all the threads finished
QtCore.QCoreApplication.instance().quit()
#QtCore.Slot(str)
def printMessage(self, text):
sys.stdout.write(text+'\n')
sys.stdout.flush()
if __name__ == '__main__':
app = QtCore.QCoreApplication(sys.argv)
m = MainProgram()
m.startWorkers()
sys.exit(app.exec_())

Categories