主程序退出时终止线程

时间:2017-12-23 18:59:47

标签: python multithreading python-3.6

我正在尝试在Python中开始使用多线程。我有多个线程获取锁,执行操作,释放锁,并将结果输出到csv文件。如果主线程完成,则应终止线程(例如,通过按Ctrl + C)。这是怎么做到的?

我认为使线程守护进程应该完成这项工作,因为“当只剩下守护进程线程时,整个Python程序退出”(官方Python文档)。这还不够。根据{{​​3}},然后我尝试捕获KeyboardInterrupt,然后手动终止线程。这也不起作用,似乎没有正确捕获KeyboardInterrupt。

这让我觉得,在Python中有一些关于多线程的东西,我误解了......找到附加的代码:

import random
import csv
import sys
from datetime import datetime
import threading

lock = threading.Lock()

def observer(obs):
    print("In " + str(obs))
    sys.stdout.flush()        

    with open("data/test_" + str(obs) + ".csv", 'a', newline='') as csvfile:
        while True:
            datenow = datetime.today()        
            lock.acquire()
            print(str(obs) + "acquired")
            sum = 0
            for i in range(10000):
                sum = sum + random.random()
            print(str(obs) + "released")
            sys.stdout.flush()
            lock.release()

            writer = csv.writer(csvfile, delimiter=',', quoting=csv.QUOTE_ALL)
            writer.writerow([datenow.isoformat(), sum/10000])
            #print(str(obs) + ": " + datenow.isoformat() + " " + str(sum/1000))
            sys.stdout.flush()

if __name__ == "__main__":
    observe = [1, 2, 3, 4]

    processes = []
    for obs in observe:
        process = threading.Thread(target=observer, args=(obs,), daemon=True)
        processes.append(process)

    print("Start processes")
    for p in processes:
        p.start()

    print("Started")
    try:
        for p in processes:
            p.join()
    except KeyboardInterrupt:
        for p in processes:
            p.terminate()
        print("Keyboard interrupt")

    print("Finished")

谢谢!

1 个答案:

答案 0 :(得分:0)

错误

try:
    for p in processes:
        p.join()
except KeyboardInterrupt:
    for p in processes:
        p.terminate()
    print("Keyboard interrupt")

您的主题永远不会退出while True:循环,因此您将永远加入它们。但那不是重点。

如果没有抓住Ctrl-C(又名KeyboardInterrupt),我最好的选择是:

  • 您正在Windows
  • 下运行Python
  • 运行脚本的shell操纵进程,实际上您从未看到Ctrl-C因为您的程序被突然终止。

你的问题是:

  • 您的程序实际上并不知道它已经终止,这就是线程挂起的原因。

如果上述假设是正确的,请尝试使用此代码(来自Python - Windows - Exiting Child Process when "unrelated" parent dies/crashes

import sys

def win_wait_for_parent(raise_exceptions=False):
    if not sys.platform == 'win32':
        return True

    # When started under cygwin, the parent process will die leaving a child
    # hanging around. The process has to be waited upon
    import ctypes
    from ctypes.wintypes import DWORD, BOOL, HANDLE
    import os
    import threading

    INFINITE = -1
    SYNCHRONIZE = 0x00100000

    kernel32 = ctypes.WinDLL('kernel32', use_last_error=True)

    kernel32.OpenProcess.argtypes = (DWORD, BOOL, DWORD)
    kernel32.OpenProcess.restype = HANDLE

    kernel32.WaitForSingleObject.argtypes = (HANDLE, DWORD)
    kernel32.WaitForSingleObject.restype = DWORD

    phandle = kernel32.OpenProcess(SYNCHRONIZE, 0, os.getppid())

    def check_parent():
        # Get a token with right access to parent and wait for it to be
        # signaled (die). Exit ourselves then
            kernel32.WaitForSingleObject(phandle, INFINITE)
            os._exit(0)

    if not phandle:
        if raise_exceptions:
            raise ctypes.WinError(ctypes.get_last_error())

        return False