Python-正在终止未正确引用SIGINT-global变量的线程
我正在努力使我的线程可以捕捉到一个信号。在我看来,kill_received singleton list与signal_handler和do_uploads在同一个名称空间中,并且引用了同一个内存位置。但当我在C运行时控制它时,我看到从print kill_received[0]打印False,而这应该是真的,因为我点击了control-CPython-正在终止未正确引用SIGINT-global变量的线程,python,multithreading,sigint,Python,Multithreading,Sigint,我正在努力使我的线程可以捕捉到一个信号。在我看来,kill_received singleton list与signal_handler和do_uploads在同一个名称空间中,并且引用了同一个内存位置。但当我在C运行时控制它时,我看到从print kill_received[0]打印False,而这应该是真的,因为我点击了control-C kill_received = [False] def signal_handler(signal, frame): global kill_r
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 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)
更新:
仍然没有成功,但我更改了语法,因为它更干净:
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()
你看到虚假打印的原因是因为它从来没有机会打印它。您在每次点击打印kill_收到[0]语句之前将其杀死 想想看。在执行以下语句之间,很可能会按Ctrl-C键:
while True and not kill_received[0]:
print kill_received[0]
本声明:
while True and not kill_received[0]:
print kill_received[0]
但这是不可能的。在任何其他时间中断任何线程都会导致它们停止while语句中的循环,并且永远不会打印任何内容
编辑:您有一行:kill_received=False,这可能会导致您出现问题。它可能应该是kill_received[0]=False您看到False打印的原因是因为它从来没有机会打印它。您在每次点击打印kill_收到[0]语句之前将其杀死 想想看。在执行以下语句之间,很可能会按Ctrl-C键:
while True and not kill_received[0]:
print kill_received[0]
本声明:
while True and not kill_received[0]:
print kill_received[0]
但这是不可能的。在任何其他时间中断任何线程都会导致它们停止while语句中的循环,并且永远不会打印任何内容
编辑:您有一行:kill_received=False,这可能会导致您出现问题。可能应该是kill_received[0]=False了解发生了什么的关键是你所做的评论
不。当所有线程都完成时,我会…但不是在线程执行期间,它们必须上载所有文件 这一行代码:
q.join()
与您可能期望的相反,control-C不会导致它停止等待队列-直到此调用返回后,它才会接受control-C。因此,发生的情况是,您的所有线程都完成了任务并清空了队列,然后正在排队等待
item = q.get()
只有在最后一个线程调用q.task_done之后,主线程才会返回,然后处理control-C。然而,在这一点上,所有线程都被困在队列中等待更多它们无法获得的项目,因此它们永远不会退出循环
这里可能会发生比这更多的事情,但要确定这是否是问题所在,请尝试在繁忙的等待中等待队列为空:
while not q.empty():
time.sleep(0.1)
q.join()
之后需要加入,因为队列为空意味着最后一次上载已从队列中拉出来,而不是它已完成
您还可以向队列中添加一个项目,表示线程应该完成,例如None。比如说,
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)
当然,这假定None不是要上载的有效值。这对control-C问题没有帮助,但您可能会发现,确保程序正常完成时线程退出是有帮助的
作为一般帮助,当您使用线程进行测试时,有一种方法可以打印出所有线程的堆栈跟踪可能会很有帮助。谈论如何做到这一点。了解发生了什么的关键是你所做的评论
不。当所有线程都完成时,我会…但不是在线程执行期间,它们必须上载所有文件 这一行代码:
q.join()
与您可能期望的相反,control-C不会导致它停止等待队列-直到此调用返回后,它才会接受control-C。因此,发生的情况是,您的所有线程都完成了任务并清空了队列,然后正在排队等待
item = q.get()
只有在最后一个线程调用q.task_done之后,主线程才会返回,然后处理control-C。然而,在这一点上,所有线程都被困在队列中等待更多它们无法获得的项目,因此它们永远不会退出循环
这里可能会发生比这更多的事情,但要确定这是否是问题所在,请尝试在繁忙的等待中等待队列为空:
while not q.empty():
time.sleep(0.1)
q.join()
之后需要加入,因为队列为空意味着最后一次上载已从队列中拉出来,而不是它已完成
您还可以向队列中添加一个项目,表示线程应该完成,例如None。比如说,
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)
当然,这假定None不是要上载的有效值。这对control-C问题没有帮助,但您可能会发现,确保程序正常完成时线程退出是有帮助的
作为一般帮助,当您使用线程进行测试时,有一种方法可以打印出所有线程的堆栈跟踪可能会很有帮助。谈论如何做到这一点
.您是否曾看到您按Ctrl+C!?不。当所有线程都已完成时,我会…但不是在线程执行期间,它们必须上载所有文件。您是否已将kill_received=False行修复为kill_received[0]=False,然后重试?您是否曾看到您按Ctrl+C!的消息!?否。当所有线程都完成时,我会…但不是在线程执行期间,它们必须上载所有文件。是否已修复kill_received=False行以kill_received[0]=False,然后重试?否,线程正在继续,并在循环继续时打印False。while True和not kill_received仍为True,因此线程将继续。@是否可以尝试在while循环后添加行打印检查:%s“%kill_received[0],以查看它们是否正在退出loop@Rob,试过这个。我把它放在while循环之后,但是它从来没有运行过,所以循环永远不会退出。不,线程正在继续,并且随着循环的继续打印False。while True和not kill_received仍为True,因此线程将继续。@是否可以尝试在while循环后添加行打印检查:%s“%kill_received[0],以查看它们是否正在退出loop@Rob,试过这个。我把它放在while循环之后,但是它从来没有运行过,所以循环从来没有退出过。呃……经过多次不同的尝试,在这方面没有获胜的机会。如果收到信号,是否有办法释放q.join?@dman使用time.sleep循环无效?如果您有足够的线程/足够少的作业,那么队列将很快清空。您是否尝试过只使用一个或两个工作线程来处理相当多的作业?您也可以尝试使用while q.unfinishedtasks:作为循环条件。呃……在多次不同的尝试之后,在这方面没有赢家。如果收到信号,是否有办法释放q.join?@dman使用time.sleep循环无效?如果您有足够的线程/足够少的作业,那么队列将很快清空。您是否尝试过只使用一个或两个工作线程来处理相当多的作业?您还可以尝试使用whileq.unfinishedtasks:作为循环条件。