How to Interrupt/Stop/End a hanging multi-threaded python program - python

I have a python program that implements threads like this:
class Mythread(threading.Thread):
def __init__(self, name, q):
threading.Thread.__init__(self)
self.name = name
self.q = q
def run(self):
print "Starting %s..." % (self.name)
while True:
## Get data from queue
data = self.q.get()
## do_some_processing with data ###
process_data(data)
## Mark Queue item as done
self.q.task_done()
print "Exiting %s..." % (self.name)
def call_threaded_program():
##Setup the threads. Define threads,queue,locks
threads = []
q = Queue.Queue()
thread_count = n #some number
data_list = [] #some data list containing data
##Create Threads
for thread_id in range(1, thread_count+1):
thread_name = "Thread-" + str(thread_id)
thread = Mythread(thread_name,q)
thread.daemon = True
thread.start()
##Fill data in Queue
for data_item in data_list:
q.put(data_item)
try:
##Wait for queue to be exhausted and then exit main program
q.join()
except (KeyboardInterrupt, SystemExit) as e:
print "Interrupt Issued. Exiting Program with error state: %s"%(str(e))
exit(1)
The call_threaded_program() is called from a different program.
I have the code working under normal circumstances. However if an error/exception occurs in one of the threads, then the program is stuck (as the queue join is infinitely blocking). The only way I am able to quit this program is to close the terminal itself.
What is the best way to terminate this program when a thread bails out? Is there a clean (actually I would take any way) way of doing this? I know this question has been asked numerous times, but I am still unable to find a convincing answer. I would really appreciate any help.
EDIT:
I tried removing the join on the queue and used a global exit flag as suggested in Is there any way to kill a Thread in Python?
However, Now the behavior is so strange, I can't comprehend what is going on.
import threading
import Queue
import time
exit_flag = False
class Mythread (threading.Thread):
def __init__(self,name,q):
threading.Thread.__init__(self)
self.name = name
self.q = q
def run(self):
try:
# Start Thread
print "Starting %s...."%(self.name)
# Do Some Processing
while not exit_flag:
data = self.q.get()
print "%s processing %s"%(self.name,str(data))
self.q.task_done()
# Exit thread
print "Exiting %s..."%(self.name)
except Exception as e:
print "Exiting %s due to Error: %s"%(self.name,str(e))
def main():
global exit_flag
##Setup the threads. Define threads,queue,locks
threads = []
q = Queue.Queue()
thread_count = 20
data_list = range(1,50)
##Create Threads
for thread_id in range(1,thread_count+1):
thread_name = "Thread-" + str(thread_id)
thread = Mythread(thread_name,q)
thread.daemon = True
threads.append(thread)
thread.start()
##Fill data in Queue
for data_item in data_list:
q.put(data_item)
try:
##Wait for queue to be exhausted and then exit main program
while not q.empty():
pass
# Stop the threads
exit_flag = True
# Wait for threads to finish
print "Waiting for threads to finish..."
while threading.activeCount() > 1:
print "Active Threads:",threading.activeCount()
time.sleep(1)
pass
print "Finished Successfully"
except (KeyboardInterrupt, SystemExit) as e:
print "Interrupt Issued. Exiting Program with error state: %s"%(str(e))
if __name__ == '__main__':
main()
The program's output is as below:
#Threads get started correctly
#The output also is getting processed but then towards the end, All i see are
Active Threads: 16
Active Threads: 16
Active Threads: 16...
The program then just hangs or keeps on printing the active threads. However since the exit flag is set to True, the thread's run method is not being exercised. So I have no clue as to how these threads are kept up or what is happening.
EDIT:
I found the problem. In the above code, thread's get method were blocking and hence unable to quit. Using a get method with a timeout instead did the trick. I have the code for just the run method that I modified below
def run(self):
try:
#Start Thread
printing "Starting %s..."%(self.name)
#Do Some processing
while not exit_flag:
try:
data = self.q.get(True,self.timeout)
print "%s processing %s"%(self.name,str(data))
self.q.task_done()
except:
print "Queue Empty or Timeout Occurred. Try Again for %s"%(self.name)
# Exit thread
print "Exiting %s..."%(self.name)
except Exception as e:
print "Exiting %s due to Error: %s"%(self.name,str(e))

If you want to force all the threads to exit when the process exits, you can set the "daemon" flag of the thread to True before the thread is created.
http://docs.python.org/2/library/threading.html#threading.Thread.daemon

I did it once in C. Basically i had a main process that were starting the other ones and kept tracks of them, ie. stored the PID and waited for the return code. If you have an error in a process the code will indicate so and then you can stop every other process. Hope this helps
Edit:
Sorry i can have forgotten in my answer that you were using threads. But I think it still applies. You can either wrap or modify the thread to get a return value or you can use the multithread pool library.
how to get the return value from a thread in python?
Python thread exit code

Related

Why does my multiprocess queue not appear to be thread safe?

I am building a watchdog timer that runs another Python program, and if it fails to find a check-in from any of the threads, shuts down the whole program. This is so it will, eventually, be able to take control of needed communication ports. The code for the timer is as follows:
from multiprocessing import Process, Queue
from time import sleep
from copy import deepcopy
PATH_TO_FILE = r'.\test_program.py'
WATCHDOG_TIMEOUT = 2
class Watchdog:
def __init__(self, filepath, timeout):
self.filepath = filepath
self.timeout = timeout
self.threadIdQ = Queue()
self.knownThreads = {}
def start(self):
threadIdQ = self.threadIdQ
process = Process(target = self._executeFile)
process.start()
try:
while True:
unaccountedThreads = deepcopy(self.knownThreads)
# Empty queue since last wake. Add new thread IDs to knownThreads, and account for all known thread IDs
# in queue
while not threadIdQ.empty():
threadId = threadIdQ.get()
if threadId in self.knownThreads:
unaccountedThreads.pop(threadId, None)
else:
print('New threadId < {} > discovered'.format(threadId))
self.knownThreads[threadId] = False
# If there is a known thread that is unaccounted for, then it has either hung or crashed.
# Shut everything down.
if len(unaccountedThreads) > 0:
print('The following threads are unaccounted for:\n')
for threadId in unaccountedThreads:
print(threadId)
print('\nShutting down!!!')
break
else:
print('No unaccounted threads...')
sleep(self.timeout)
# Account for any exceptions thrown in the watchdog timer itself
except:
process.terminate()
raise
process.terminate()
def _executeFile(self):
with open(self.filepath, 'r') as f:
exec(f.read(), {'wdQueue' : self.threadIdQ})
if __name__ == '__main__':
wd = Watchdog(PATH_TO_FILE, WATCHDOG_TIMEOUT)
wd.start()
I also have a small program to test the watchdog functionality
from time import sleep
from threading import Thread
from queue import SimpleQueue
Q_TO_Q_DELAY = 0.013
class QToQ:
def __init__(self, processQueue, threadQueue):
self.processQueue = processQueue
self.threadQueue = threadQueue
Thread(name='queueToQueue', target=self._run).start()
def _run(self):
pQ = self.processQueue
tQ = self.threadQueue
while True:
while not tQ.empty():
sleep(Q_TO_Q_DELAY)
pQ.put(tQ.get())
def fastThread(q):
while True:
print('Fast thread, checking in!')
q.put('fastID')
sleep(0.5)
def slowThread(q):
while True:
print('Slow thread, checking in...')
q.put('slowID')
sleep(1.5)
def hangThread(q):
print('Hanging thread, checked in')
q.put('hangID')
while True:
pass
print('Hello! I am a program that spawns threads!\n\n')
threadQ = SimpleQueue()
Thread(name='fastThread', target=fastThread, args=(threadQ,)).start()
Thread(name='slowThread', target=slowThread, args=(threadQ,)).start()
Thread(name='hangThread', target=hangThread, args=(threadQ,)).start()
QToQ(wdQueue, threadQ)
As you can see, I need to have the threads put into a queue.Queue, while a separate object slowly feeds the output of the queue.Queue into the multiprocessing queue. If instead I have the threads put directly into the multiprocessing queue, or do not have the QToQ object sleep in between puts, the multiprocessing queue will lock up, and will appear to always be empty on the watchdog side.
Now, as the multiprocessing queue is supposed to be thread and process safe, I can only assume I have messed something up in the implementation. My solution seems to work, but also feels hacky enough that I feel I should fix it.
I am using Python 3.7.2, if it matters.
I suspect that test_program.py exits.
I changed the last few lines to this:
tq = threadQ
# tq = wdQueue # option to send messages direct to WD
t1 = Thread(name='fastThread', target=fastThread, args=(tq,))
t2 = Thread(name='slowThread', target=slowThread, args=(tq,))
t3 = Thread(name='hangThread', target=hangThread, args=(tq,))
t1.start()
t2.start()
t3.start()
QToQ(wdQueue, threadQ)
print('Joining with threads...')
t1.join()
t2.join()
t3.join()
print('test_program exit')
The calls to join() means that the test program never exits all by itself since none of the threads ever exit.
So, as is, t3 hangs and the watchdog program detects this and detects the unaccounted for thread and stops the test program.
If t3 is removed from the above program, then the other two threads are well behaved and the watchdog program allows the test program to continue indefinitely.

Python multiprocessing fails randomly and silently

I am a php developer trying to wing a python multiprocessing script. It is creating a queue that needs to be 40,000+ items long. The queue fills fine, but my processes die silently and randomly. Tried in 2.6 and 2.7.
I have put logging throughout to try to diagnose what is happening, to no avail. On random entries with no discernible data problems, all child processes will stop and the main thread will exit? Note: it is the SAME entries that it fails on, regardless of start point, unless it is under 20 entries being read.
Sometimes it will do 150 entries, sometimes 50 before it quits. Since I need it to do 40k, this is a deal-breaker. The script has no problem doing 20 or so, and logs the proper process starting and exiting messages. When it fails, there is not process exit logged.
My code is too sensitive to post, but here is the basic model I used, taken from a tutorial on multithreading and converted to the mutliprocessing module. Basically, just replaced "threading" with "multiprocessing" and used multiprocessing's Queue instead of the module Queue.
import Queue
import threading
import time
exitFlag = 0
class myThread (threading.Thread):
def __init__(self, threadID, name, q):
threading.Thread.__init__(self)
self.threadID = threadID
self.name = name
self.q = q
def run(self):
print "Starting " + self.name
process_data(self.name, self.q)
print "Exiting " + self.name
def process_data(threadName, q):
while not exitFlag:
queueLock.acquire()
if not workQueue.empty():
data = q.get()
queueLock.release()
print "%s processing %s" % (threadName, data)
else:
queueLock.release()
time.sleep(1)
threadList = ["Thread-1", "Thread-2", "Thread-3"]
nameList = ["One", "Two", "Three", "Four", "Five"]
queueLock = threading.Lock()
workQueue = Queue.Queue(10)
threads = []
threadID = 1
# Create new threads
for tName in threadList:
thread = myThread(threadID, tName, workQueue)
thread.start()
threads.append(thread)
threadID += 1
# Fill the queue
queueLock.acquire()
for word in nameList:
workQueue.put(word)
queueLock.release()
# Wait for queue to empty
while not workQueue.empty():
pass
# Notify threads it's time to exit
exitFlag = 1
# Wait for all threads to complete
for t in threads:
t.join()
print "Exiting Main Thread"
Turns out, I installed 32-bit python on a 64-bit windows machine accidentally. Strange behavior ensued, mostly from the multiprocessing module. Uninstalling 32-bit and installing 64-bit python 2.7.10 made it work correctly.
So if nothing makes sense with how your code is executing, maybe you've got the wrong interpreter!

Python exiting multiple threads

I'm trying to see how multi thread are working in order to use them in an automation project. I can run the thread but I cannot find a way to exit completely the two threads: the thread restart after each keyboard interupt. Is there a way to exit both thread with a keyboard interupt ?
import thread
from time import sleep
*parameters when starting
temp_c = 32
T_hot = 30
T_cold = 27
interval_temp = 2
def ctrl_fan(temp_c, T_hot,interval_temp):
while True:
if temp_c >= T_hot:
print 'refreshing'
else:
print ' fan stopped'
sleep(interval_temp)
print 'shutting everything off'
def ctrl_light(temp_c, T_cold,interval_temp):
while True:
if temp_c <= T_cold:
print 'warming'
else:
print 'light stopped'
sleep(interval_temp)
print 'shutting everything off'
try:
thread.start_new_thread(ctrl_fan, (temp_c, T_hot,interval_temp, ) )
sleep(1)
thread.start_new_thread(ctrl_light, (temp_c, T_cold,interval_temp, ) )
except (KeyboardInterrupt, SystemExit):
thread.exit()
print "Error: unable to start thread"
Sure,
Firstly I'd recommend using the slightly higher level threading module instead of the thread module.
To start a thread with threading use the following
import threading
t = threading.Thread(target=ctrl_fan, args=(temp_c, T_hot, interval_temp))
t.start()
There's a few things you'll need to do to get the program to exit with a Ctrl-C interupt.
Firstly you will want to set the threads to be daemon, so that they allow the program to exit when the main thread exits (t.daemon = True)
You will also want the main thread to wait on the completion of the threads, you can use t.join() to do this. However this wont raise out a KeyboardInterrupt exception until the thread finishes, there is a work around for this though
while t.is_alive():
t.join(1)
Providing a timeout value gets around this.
I'd be tempted to pull this together into a subclass, to get the behaviour you want
import threading
class CustomThread(threading.Thread):
def __init__(self, *args, **kwargs):
threading.Thread.__init__(self, *args, **kwargs)
self.daemon = True
def join(self, timeout=None):
if timeout is None:
while self.is_alive():
threading.Thread.join(self, 10)
else:
return threading.Thread.join(self, timeout)
t1 = CustomThread(target=ctrl_fan, args=(temp_c, T_hot, interval_temp))
t1.start()
t2 = CustomThread(target=ctrl_light, args=(temp_c, T_cold, interval_temp))
t2.start()
t1.join()
t2.join()
The explanation is, again, in the documentation (https://docs.python.org/2/library/thread.html) :
Threads interact strangely with interrupts: the KeyboardInterrupt exception will be received by an arbitrary thread. (When the signal module is available, interrupts always go to the main thread.)
You'd certainly find answers in https://stackoverflow.com/, like :
Propagate system call interruptions in threads

Python- Killing Threads with SIGINT- global variable not being referenced correctly

I am trying to make it to where my threads can catch a sigint. It looks like to me that kill_received singleton list is in the same namespace of signal_handler() and do_the_uploads() and the same memory location is being referenced. But when I control C when it's running, I see False being printed from "print kill_received[0]" when it should be True since I hit control-C.
kill_received = [False]
def signal_handler(signal, frame):
global kill_received
kill_received[0] = True
print "\nYou pressed Ctrl+C!"
print (
"Your logs and their locations are:"
"\n{}\n{}\n{}".format(debug, error, info))
sys.exit(0)
def do_the_uploads(file_list, file_quantity,
retry_list, authenticate):
"""The uploading engine"""
value = raw_input(
"\nPlease enter how many conncurent "
"uploads you want at one time(example: 200)> ")
value = int(value)
logger.info('{} conncurent uploads will be used.'.format(value))
confirm = raw_input(
"\nProceed to upload files? Enter [Y/y] for yes: ").upper()
if confirm == "Y":
kill_received = False
sys.stdout.write("\x1b[2J\x1b[H")
q = Queue.Queue()
def worker():
global kill_received
while True and not kill_received[0]:
print kill_received[0]
item = q.get()
upload_file(item, file_quantity, retry_list, authenticate)
q.task_done()
for i in range(value):
t = Thread(target=worker)
t.setDaemon(True)
t.start()
for item in file_list:
q.put(item)
q.join()
print "Finished. Cleaning up processes...",
#Allowing the threads to cleanup
time.sleep(4)
print "done."
From main script:
from modules.upload_actions import do_the_uploads, retry, signal_handler
if __name__ == '__main__':
signal.signal(signal.SIGINT, signal_handler)
retry_list = []
file_list, authenticate, ticket_number = main()
file_quantity = FileQuantity(len(file_list))
do_the_uploads(file_list, file_quantity,
retry_list, authenticate)
Update:
Still no success, but I changed the syntax to this as it's cleaner:
def worker():
global kill_received
while not kill_received[0]:
time.sleep(1)
print kill_received[0]
item = q.get()
upload_file(item, file_quantity, retry_list, authenticate)
q.task_done()
The key to understanding what is going on is the comment you made
No. When the threads are all completed then I do...but not during thread execution for all the files they have to upload.
and this line of code:
q.join()
Contrary to what you are probably expecting, a control-C does NOT cause it to stop waiting for the queue - it doesn't accept the control-C until after this call has returned. So what is happening is that all of your threads have done their jobs and emptied the queue, and then are waiting on the line
item = q.get()
Only after the last thread calls q.task_done does the main thread return and then process the control-C. However, at that point all the threads are stuck waiting for more items from the queue (which they aren't going to get), so they will never exit the loop.
There might be more going on here than this, but to see if this is the problem try a busy wait for the queue to be empty:
while not q.empty():
time.sleep(0.1)
q.join()
You need the join afterward because the queue being empty means the last upload has been pulled from the queue, not that it has been finished.
One other thing you can add is an item to the queue that signals the thread should finish, such as None. For example,
def worker():
global kill_received
while True and not kill_received[0]:
print kill_received[0]
item = q.get()
if item is None:
q.task_done()
break
upload_file(item, file_quantity, retry_list, authenticate)
q.task_done()
for i in range(value):
t = Thread(target=worker)
t.setDaemon(True)
t.start()
for item in file_list:
q.put(item)
for i in range(value):
q.put(None)
Of course, this assumes that None is not a valid value to upload. This won't help with the control-C issue, but it is something you might find helpful to make sure that the threads exit when the program finishes normally.
As a general help, when you testing things with threads it can be helpful to have a way to print out stack traces for all threads. This SO question talks about how to do that.
The reason you see False printed is because it never gets a chance to print it. You killed it before it every hits your print kill_received[0] statement.
Think about it. There is probably a small chance that you could hit Ctrl-C between execution of this statement:
while True and not kill_received[0]:
and this statement:
print kill_received[0]
but it's improbable. Interrupting any of the threads at any other time will cause them to stop looping (from your while statement), and never print anything.
EDIT: You have the line: kill_received = False which may be causing you issues. It should probably be kill_received[0] = False

Python: How to terminate a blocking thread [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Is there any way to kill a Thread in Python?
So this question is a follow up to a solution posted previously. Basically it deals with programatically terminating a thread: http://sebulba.wikispaces.com/recipe+thread2
However it doesnt work... and I was wondering if someone can explain how one could terminate a thread that is blocking? My only guess is the fact that I am not providing the right thread id, but I did some testing and am pretty sure I can just use iden
If it is the thread ID, how can I go about getting the correct Thread ID?
Test Code:
class BlockingTestThread(Thread):
def __init__(self):
self._running_flag = False
Thread.__init__(self, target=self.test_method)
def test_method(self):
try:
while(not self.stopped()):
self._running_flag = True
time.sleep(100)
finally:
self._running_flag = False
def _async_raise(tid, exctype):
'''Raises an exception in the threads with id tid'''
if not inspect.isclass(exctype):
raise TypeError("Only types can be raised (not instances)")
res = ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(exctype))
time.sleep(0.1)
if __name__ == "__main__":
thread = BlockingTestThread()
thread.start()
_async_raise(thread.ident, SystemExit)
print "Joining thread"
thread.join()
print "Done Joining thread"
#will never get here!
Here is a better way to do it, use the "wait" command on the event, asssuming you want to use sleep.
class BlockingTestThread(Thread):
def __init__(self):
self._running_flag = False
self.stop = threading.Event()
Thread.__init__(self, target=self.test_method)
def test_method(self):
try:
while(not self.stop.wait(1)):
self._running_flag = True
print 'Start wait'
self.stop.wait(100)
print 'Done waiting'
finally:
self._running_flag = False
def terminate(self):
self.stop.set()
if __name__ == "__main__":
thread = BlockingTestThread()
thread.start()
time.sleep(2)
print 'Time sleep 2'
thread.terminate()
print "Joining thread"
thread.join()
print "Done Joining thread"
Obviously you are going to need to wrap your blocking thread in something that uses the pattern above, but if you can't the other option is to cause your process to throw an exception, in our case we basically kill the underlying connection, which causes an exception, and when that exception happens if the stopped flag is set, we ignore it.
You are right about ident, from the docs, ident variable doesn't map to thread id, it's just a reference-
thread.get_ident()
Return the ‘thread identifier’ of the current thread. This is a nonzero integer. Its value has no direct meaning; it is intended as a magic cookie to be used e.g. to index a dictionary of thread-specific data. Thread identifiers may be recycled when a thread exits and another thread is created.
See http://bytes.com/topic/python/answers/45247-terminating-thread-parent re: killling, not sure if it's exactly what you are looking for unfortunately.

Categories