I am launching a main Thread from my Python 3.4 program that launches various subthreads (in this case daemon threads).
I would like to kill the main thread and start it back up again.
For some reason this is an incredibly difficult task. Before someone suggests that I use a multiprocessing.Process and Process.terminate() instead of a Thread, I am unable to go this route because my real program has to share a common sqlite3 connection with all the threads and subthreads, which I cannot do using processes.
Currently, I am using a Queue to signal to the main thread that it should exit using sys.exit(), but this does not work, as you can see below. I've tried os._exit(0) instead, but that kills the whole interpreter.
import sys
import time
from threading import Thread
from queue import Queue
t = None
q = None
def subthread1():
while True:
time.sleep(2)
print(' 1...')
def subthread2():
while True:
time.sleep(2)
print(' 2...')
def main_thread(q):
t1 = Thread(target=subthread1)
t1.daemon = True
t1.start()
t2 = Thread(target=subthread2)
t2.daemon = True
t2.start()
while True:
msg = q.get()
if msg == 0:
print("EXITING THREAD")
sys.exit()
def start():
print("STARTING")
global q, t
q = Queue()
t = Thread(target=main_thread, args=(q,))
t.start()
def kill():
print("KILLING")
global q, t
q.put(0)
def main():
start()
time.sleep(10)
kill()
time.sleep(10)
start()
if __name__ == '__main__':
main()
This produces output:
STARTING
1...
2...
1...
2...
2...
1...
1...
2...
2...
1...
KILLING
EXITING THREAD
2...
1...
1...
2...
2...
1...
2...
1...
STARTING
2...
1...
2...
1...
2...
1...
2...
1...
2...
1...
1...
2...
1...
2...
1...
I want the main thread, including all subthreads, to exit, and then start up again. How can I achieve this? In my real program my subthreads have subthreads (all daemon). Any help greatly appreciated!
You just need a way to tell the subthreads to stop. I'd do it this way:
def subthread1(stop):
while not stop:
time.sleep(1)
print(' 1...')
def main_thread(q):
stop = [] # list rather than boolean because we need it "by reference"
t1 = Thread(target=subthread1, args=(stop,))
t1.daemon = True
t1.start()
while True:
msg = q.get()
if msg == 0:
print("EXITING THREAD")
stop.append(True)
break
Note that I simply use break instead of sys.exit(), but it works either way. You might also consider doing t1.join() before main_thread() exits, if you want to wait for the subthreads to clean up.
Related
I am trying to grasp the Lock in multithreading module in python. But for some reason it is not locking the objects and lets the next thread run without waiting for the lock to release.
Here is the code:
from threading import Thread, Lock
import time
database_value = 0
def increase(lock):
global database_value
lock.acquire()
local_copy = database_value
local_copy += 1
time.sleep(0.1)
database_value = local_copy
lock.release()
if __name__ == '__main__':
lock = Lock()
print('start value',database_value)
thread1 = Thread(target =increase, args = (lock,))
thread2 = Thread(target =increase, args = (lock,))
print('start')
#start
thread1.start()
thread2.start()
#join
print('join')
thread1.join()
thread1.join()
print('end value', database_value)
The Output I am expecting is:
start value 0
start
join
end value 2
But the Output I get:
start value 0
start
join
end value 1
At the join step, you wait for thread1 instead of thread2.
#join
print('join')
thread1.join()
thread1.join() # Should be thread2
If you change it below, it will work.
#join
print('join')
thread1.join()
thread2.join()
I am trying to start a thread to listen to the incoming messages from a socket. so it contains an infinite loop. but when I try to close the gui, it hangs there, and does not close it. here is more simplified code without using any gui.
import threading,time,sys
def f(x):
while True:
time.sleep(0.5)
print(x)
timer = threading.Timer(0.1,f,("some text",) )
timer.start()
time.sleep(2)
print("time to stop")
sys.exit()
as you see the line sys.exit() won't end all threads (main thread and thread started by timer).
now I was wondering how to kill that specific thread which started by the timer.
thank you for your help
I finally find a solution for it. somehow we can use global variables to end an endless loop inside a thread, and therefore close it.
import threading,time
def f(x):
global z
while True:
time.sleep(0.5)
print(x)
if not z:
break
global z
z = True
timer = threading.Timer(0.1,f,("some text",) )
timer.start()
time.sleep(2)
print("time to stop")
z = False
I want to know how to stop a running function outside of it. Here is how it should be:
def smth():
time.sleep(5) # Just an example
smth.stop()
Thanks for your help
Here's an example using the multiprocessing library:
from multiprocessing import Process
import time
def foo():
print('Starting...')
time.sleep(5)
print('Done')
p = Process(target=foo) #make process
p.start() #start function
time.sleep(2) #wait 2 secs
p.terminate() #kill it
print('Killed')
Output:
Starting...
Killed
Basically, what this code does is:
Create a process p which runs the function foo when started
Wait 2 seconds to simulate doing other stuff
End the process p with p.terminate()
Since p never passes time.sleep(5) in foo, it doesn't print 'Done'
Run this code online
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 am trying to write function using Python multiprocessing that i can control it and pass "command" to cleanly terminate the process.
I looked for few examples and tried it out ,but didn't seems to work fro me
So basically i need to to run separate process function code that doing some while loop action
and when needed stop it by passing somehow command and exit
Please advice
Thanks
example 1
from multiprocessing import Process, Queue
def start_process(queue):
while True:
try:
m = queue.get()
if m == 'exit':
print ('cleaning up worker...')
# add here your cleaning up code
break
else:
print (m)
except KeyboardInterrupt:
print ('ignore CTRL-C from worker')
if __name__ == '__main__':
queue = Queue()
process = Process(target=start_process, args=(queue,))
process.start()
queue.put(12)
try:
process.join()
except KeyboardInterrupt:
print ('wait for worker to cleanup...')
queue.put('exit')
process.join()
example 2
import multiprocessing
import time
class MyProcess(multiprocessing.Process):
def __init__(self, ):
multiprocessing.Process.__init__(self)
self.exit = multiprocessing.Event()
def run(self):
while not self.exit.is_set():
pass
print ("You exited!")
def shutdown(self):
print ("Shutdown initiated")
self.exit.set()
if __name__ == "__main__":
process = MyProcess()
process.start()
print ("Waiting for a while")
time.sleep(3)
process.shutdown()
time.sleep(3)
print ("Child process state: %d" % process.is_alive())
both examples works fine for me - perhaps you're misunderstanding how they should work?
in the first example, when the main thread runs, it starts the child and sends 12. then it waits to join the child. at that point everything is stalled because the child is waiting for 'exit'. but if you then hit ctrl-C the 'exit' is sent, the child exits, and the second join is successful:
> python3.3 example1.py
12
^Cignore CTRL-C from worker
wait for worker to cleanup...
cleaning up worker...
>
if you just want the parent to send 'exit' and then for everything to end, use:
def start_process(queue):
while True:
try:
m = queue.get()
if m == 'exit':
print ('cleaning up worker...')
# add here your cleaning up code
break
else:
print (m)
except KeyboardInterrupt:
print ('ignore CTRL-C from worker')
print('goodbye cruel world')
if __name__ == '__main__':
queue = Queue()
process = Process(target=start_process, args=(queue,))
process.start()
queue.put(12)
print ('sending exit')
queue.put('exit')
process.join()
which gives:
> python3.3 my-example.py
sending exit
12
cleaning up worker...
goodbye cruel world
>
your second example also works (with the indentation fixed):
> python3.3 example2.py
Waiting for a while
Shutdown initiated
You exited!
Child process state: 0
>
(just wait a little). not sure what else you could have expected here.