Python-杀死线程,SIGINT-全局变量未被正确引用

时间:2013-11-27 21:20:01

标签: python multithreading sigint

我正试图将它带到我的线程可以捕获sigint的位置。我认为kill_received单例列表位于signal_handler()do_the_uploads()的同一名称空间中,并且正在引用相同的内存位置。但是当我在C运行时控制C时,我看到False是从"print kill_received[0]"打印出来的,因为我点击了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 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()

2 个答案:

答案 0 :(得分:3)

理解正在发生的事情的关键是你所做的评论

  

没有。当线程全部完成后,我会...但不会在线程执行期间为他们必须上传的所有文件。

和这行代码:

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问题没有帮助,但是你可能会发现在程序正常完成时确保线程退出是有帮助的。

作为一般帮助,当您使用线程测试内容时,有一种方法可以打印出所有线程的堆栈跟踪。 This SO question讨论如何做到这一点。

答案 1 :(得分:2)

您看到False打印的原因是因为它永远不会有机会打印它。你在每次命中print kill_received[0]声明之前杀了它。

想一想。您可以在执行此语句之间按Ctrl-C的可能性很小:

while True and not kill_received[0]:

和本声明:

print kill_received[0]

但这不太可能。在任何其他时间中断任何线程将导致它们停止循环(从您的while语句),并且永远不会打印任何内容。


编辑:您有一行:kill_received = False可能会导致您遇到问题。应该是kill_received[0] = False