What should be written in kill_input() instead of pass to stop input() and terminate the program?
#!/usr/bin/env python3
import threading, time
running = True
def kill_input():
pass
def input_reader():
while running:
print(input())
t = threading.Thread(target = input_reader)
t.start()
time.sleep(2)
kill_input()
print('bye')
Solved with setting the thread to daemon.
t.daemon = True
t.start()
If there are no hanging non-daemon threads it will terminate automatically.
Related
After reading many questions about threads and .join() function, I still can not find how to adapt the basic pygobject threads example from documentation, so that it matches my use case:
#!/bin/python3
import threading
import time
from gi.repository import GLib, Gtk, GObject
def app_main():
win = Gtk.Window(default_height=50, default_width=300)
win.connect("destroy", Gtk.main_quit)
def update_progess(i):
progress.pulse()
progress.set_text(str(i))
return False
def example_target():
for i in range(50):
GLib.idle_add(update_progess, i)
time.sleep(0.2)
def start_actions(self):
print("do a few thing before thread starts")
thread = threading.Thread(target=example_target)
thread.daemon = True
thread.start()
print("do other things after thread finished")
mainBox = Gtk.Box(spacing=20, orientation="vertical")
win.add(mainBox)
btn = Gtk.Button(label="start actions")
btn.connect("clicked", start_actions)
mainBox.pack_start(btn, False, False, 0)
progress = Gtk.ProgressBar(show_text=True)
mainBox.pack_start(progress, False, False, 0)
win.show_all()
if __name__ == "__main__":
app_main()
Gtk.main()
How to make this code print "do other things after thread finished" only after my thread terminates and without freezing main window?
First, just to make it clear, the thread isn't finished after you call its start method.
Look at the definition of the code running in the thread:
def example_target():
for i in range(50):
GLib.idle_add(update_progess, i)
time.sleep(0.2)
What this does is basically repeat the following 50 times:
tell GTK to execute update_progress at the next time the system is idle (has no events to process).
sleeps for 0.2 seconds.
You could define a function after_thread, and have that scheduled when the thread finishes:
def example_target():
for i in range(50):
GLib.idle_add(update_progess, i)
time.sleep(0.2)
# loop is finished, thread will end.
GLib.idle_add(after_thread)
I have the following python program using threads. I am unable to understand why it does not terminate after execution. Suggest possible reasons and how to overcome this problem. Here is the code -
import time
from threading import *
lock1 = Lock()
def func(string):
for i in range(5):
lock1.acquire()
print(string)
lock1.release()
time.sleep(0.1)
t1 = Thread(target = func, args = ('Hello from t1',))
t2 = Thread(target = func, args = ('Hello from t2',))
t1.start()
t2.start()
print(t1.name)
The reason is simple, it is not ending because it is not making an exit from main thread. Moreover, it may run on IDLE but will not run on shell.
How can I stop or reach to avoid hanging of the following:
import threading
mythread = Threading(target = input_read, args = (callback))
mythread.start()
running = True
def callback(msg):
if msg == 'stop': running = False
print(msg)
def input_read(callback):
while running:
callback(input())
while running:
try:
# some other code
except KeyboardInterrupt:
pass
Somehow the input should be stopped, time outted, killed, anything..
Solved with setting the thread to daemon:
mythread.daemon = True
mythread.start()
Multiprocessing in python starts a new process.
Within that new process, I create 2 new threads and do nothing else in the "main thread" that started the new process, it seems that the process is gone.
Example:
new_process = multiprocessing.Process(target=new_proc_main, name=yyy)
new_process.start()
def new_proc_main():
thread1 = threading.Thread(target=xxxx, name=thread1)
thread1.start()
thread2 = threading.Thread(target=xxxx, name=thread2)
thread2.start()
How can I keep the new process alive while threads 1 & 2 run?
I wrote a test program. This is Python 3.6.2 on MacOS
import multiprocessing
import time
def new_main():
import threading
my_thread = threading.Thread(target=dummy_main)
my_thread.start()
my_thread.join()
def dummy_main():
while True:
print("thread running")
time.sleep(1)
print("start process")
p = multiprocessing.Process(target=new_main)
p.start()
The key is that I have to have my_thread.join().
If I do not have that, the program exits immediately.
I'm curious, why the code below freezes. When I kill python3 interpreter, "cat" process remains as a zombie. I expect the subprocess will be terminated before main process finished.
When I send manually SIGTERM to cat /dev/zero, the process is correctly finished (almost immediately)
#!/usr/bin/env python3
import subprocess
import re
import os
import sys
import time
from PyQt4 import QtCore
class Command(QtCore.QThread):
# stateChanged = QtCore.pyqtSignal([bool])
def __init__(self):
QtCore.QThread.__init__(self)
self.__runned = False
self.__cmd = None
print("initialize")
def run(self):
self.__runned = True
self.__cmd = subprocess.Popen(["cat /dev/zero"], shell=True, stdout=subprocess.PIPE)
try:
while self.__runned:
print("reading via pipe")
buf = self.__cmd.stdout.readline()
print("Buffer:{}".format(buf))
except:
logging.warning("Can't read from subprocess (cat /dev/zero) via pipe")
finally:
print("terminating")
self.__cmd.terminate()
self.__cmd.kill()
def stop(self):
print("Command::stop stopping")
self.__runned = False
if self.__cmd:
self.__cmd.terminate()
self.__cmd.kill()
print("Command::stop stopped")
def exitApp():
command.stop()
time.sleep(1)
sys.exit(0)
if __name__ == "__main__":
app = QtCore.QCoreApplication(sys.argv)
command = Command()
# command.daemon = True
command.start()
timer = QtCore.QTimer()
QtCore.QObject.connect(timer, QtCore.SIGNAL("timeout()"), exitApp)
timer.start(2 * 1000)
sys.exit(app.exec_())
As you noted yourself, the reason for zombie is that signal is caught by shell and doesn't effect process created by it. However there is a way to kill shell and all processes created by it; you have to use process group feature. See How to terminate a python subprocess launched with shell=True Having said that if you can manage without shell=True that's always preferable - see my answer here.
I solved this problem in a different way, so here's the result:
I have to call subprocess.Popen with shell=False, because otherwise it creates 2 processes (shell and the process) and __cmd.kill() send signal to shell while "process" remains as a zombie