确保子进程在退出 Python 程序时死亡

发布于 2024-07-08 19:30:14 字数 137 浏览 12 评论 0原文

有没有办法确保所有创建的子进程在Python程序退出时都死掉? 我所说的子进程是指那些使用 subprocess.Popen() 创建的进程。

如果不是,我是否应该迭代所有发出的kills,然后kills -9? 有什么更干净的吗?

Is there a way to ensure all created subprocess are dead at exit time of a Python program? By subprocess I mean those created with subprocess.Popen().

If not, should I iterate over all of the issuing kills and then kills -9? anything cleaner?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(15

2024-07-15 19:30:14

您可以使用 atexit 来执行此操作,并注册任何清理操作程序退出时要运行的任务。

atexit.register(func[, *args[, **kargs]])

在清理过程中,您还可以实现自己的等待,并在发生所需超时时终止它。

>>> import atexit
>>> import sys
>>> import time
>>> 
>>> 
>>>
>>> def cleanup():
...     timeout_sec = 5
...     for p in all_processes: # list of your processes
...         p_sec = 0
...         for second in range(timeout_sec):
...             if p.poll() == None:
...                 time.sleep(1)
...                 p_sec += 1
...         if p_sec >= timeout_sec:
...             p.kill() # supported from python 2.6
...     print 'cleaned up!'
...
>>>
>>> atexit.register(cleanup)
>>>
>>> sys.exit()
cleaned up!

注意 -- 如果该进程(父进程)被终止,注册的函数将不会运行。

对于 python >= 2.6 不再需要下面的 windows 方法

下面是在 windows 中杀死进程的方法。 您的 Popen 对象具有 pid 属性,因此您可以通过 success = win_kill(p.pid) 调用它(需要 pywin32 安装):

    def win_kill(pid):
        '''kill a process by specified PID in windows'''
        import win32api
        import win32con

        hProc = None
        try:
            hProc = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid)
            win32api.TerminateProcess(hProc, 0)
        except Exception:
            return False
        finally:
            if hProc != None:
                hProc.Close()

        return True

You can use atexit for this, and register any clean up tasks to be run when your program exits.

atexit.register(func[, *args[, **kargs]])

In your cleanup process, you can also implement your own wait, and kill it when a your desired timeout occurs.

>>> import atexit
>>> import sys
>>> import time
>>> 
>>> 
>>>
>>> def cleanup():
...     timeout_sec = 5
...     for p in all_processes: # list of your processes
...         p_sec = 0
...         for second in range(timeout_sec):
...             if p.poll() == None:
...                 time.sleep(1)
...                 p_sec += 1
...         if p_sec >= timeout_sec:
...             p.kill() # supported from python 2.6
...     print 'cleaned up!'
...
>>>
>>> atexit.register(cleanup)
>>>
>>> sys.exit()
cleaned up!

Note -- Registered functions won't be run if this process (parent process) is killed.

The following windows method is no longer needed for python >= 2.6

Here's a way to kill a process in windows. Your Popen object has a pid attribute, so you can just call it by success = win_kill(p.pid) (Needs pywin32 installed):

    def win_kill(pid):
        '''kill a process by specified PID in windows'''
        import win32api
        import win32con

        hProc = None
        try:
            hProc = win32api.OpenProcess(win32con.PROCESS_TERMINATE, 0, pid)
            win32api.TerminateProcess(hProc, 0)
        except Exception:
            return False
        finally:
            if hProc != None:
                hProc.Close()

        return True
故事与诗 2024-07-15 19:30:14

在 *nix 上,也许使用进程组可以帮助您 - 您也可以捕获子进程生成的子进程。

if __name__ == "__main__":
  os.setpgrp() # create new process group, become its leader
  try:
    # some code
  finally:
    os.killpg(0, signal.SIGKILL) # kill all processes in my group

另一个考虑因素是升级信号:从 SIGTERM(kill 的默认信号)到 SIGKILL(又名 kill -9)。 在信号之间等待一小会儿,让进程有机会彻底退出,然后再kill -9

On *nix's, maybe using process groups can help you out - you can catch subprocesses spawned by your subprocesses as well.

if __name__ == "__main__":
  os.setpgrp() # create new process group, become its leader
  try:
    # some code
  finally:
    os.killpg(0, signal.SIGKILL) # kill all processes in my group

Another consideration is to escalate the signals: from SIGTERM (default signal for kill) to SIGKILL (a.k.a kill -9). Wait a short while between the signals to give the process a chance to exit cleanly before you kill -9 it.

︶ ̄淡然 2024-07-15 19:30:14

subprocess.Popen.wait() 是确保它们已死亡的唯一方法。 事实上,POSIX 操作系统要求您等待您的孩子。 许多 *nix 会创建一个“僵尸”进程:一个父进程没有等待的死亡子进程。

如果子进程写得相当好,它就会终止。 通常,孩子们会从 PIPE 中阅读。 关闭输入是对孩子的一个重要暗示,它应该关闭商店并退出。

如果子进程有 bug 并且没有终止,您可能必须杀死它。 你应该修复这个错误。

如果子循环是“永远服务”循环,并且未设计为终止,则您应该终止它或提供一些输入或消息来强制其终止。


编辑。

在标准操作系统中,您有 os.kill( PID, 9 ) 。 顺便说一句,Kill -9 很严酷。 如果你可以用 SIGABRT (6?) 或 SIGTERM (15) 杀死它们,那就更有礼貌了。

在 Windows 操作系统中,您没有可用的 os.kill。 查看此ActiveState Recipe,用于终止 Windows 中的进程。

我们有作为 WSGI 服务器的子进程。 为了终止它们,我们对一个特殊的 URL 执行 GET; 这会导致孩子清理并退出。

The subprocess.Popen.wait() is the only way to assure that they're dead. Indeed, POSIX OS's require that you wait on your children. Many *nix's will create a "zombie" process: a dead child for which the parent didn't wait.

If the child is reasonably well-written, it terminates. Often, children read from PIPE's. Closing the input is a big hint to the child that it should close up shop and exit.

If the child has bugs and doesn't terminate, you may have to kill it. You should fix this bug.

If the child is a "serve-forever" loop, and is not designed to terminate, you should either kill it or provide some input or message which will force it to terminate.


Edit.

In standard OS's, you have os.kill( PID, 9 ). Kill -9 is harsh, BTW. If you can kill them with SIGABRT (6?) or SIGTERM (15) that's more polite.

In Windows OS, you don't have an os.kill that works. Look at this ActiveState Recipe for terminating a process in Windows.

We have child processes that are WSGI servers. To terminate them we do a GET on a special URL; this causes the child to clean up and exit.

霊感 2024-07-15 19:30:14

找出Linux下的解决方案(不安装prctl):

def _set_pdeathsig(sig=signal.SIGTERM):
    """help function to ensure once parent process exits, its childrent processes will automatically die
    """
    def callable():
        libc = ctypes.CDLL("libc.so.6")
        return libc.prctl(1, sig)
    return callable


subprocess.Popen(your_command, preexec_fn=_set_pdeathsig(signal.SIGTERM)) 

Find out a solution for linux (without installing prctl):

def _set_pdeathsig(sig=signal.SIGTERM):
    """help function to ensure once parent process exits, its childrent processes will automatically die
    """
    def callable():
        libc = ctypes.CDLL("libc.so.6")
        return libc.prctl(1, sig)
    return callable


subprocess.Popen(your_command, preexec_fn=_set_pdeathsig(signal.SIGTERM)) 
随梦而飞# 2024-07-15 19:30:14

警告:仅限 Linux! 您可以让您的孩子在父母去世时收到信号。

首先安装 python-prctl==1.5.0 然后更改父代码以启动子进程,如下所示

subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL))

这意味着:

  • 启动子进程:在分叉后和执行子进程之前睡眠 100
  • ,子进程注册“向我发送 SIGKILL”
    当我的父母终止时”。

Warning: Linux-only! You can make your child receive a signal when its parent dies.

First install python-prctl==1.5.0 then change your parent code to launch your child processes as follows

subprocess.Popen(["sleep", "100"], preexec_fn=lambda: prctl.set_pdeathsig(signal.SIGKILL))

What this says is:

  • launch subprocess: sleep 100
  • after forking and before exec of the subprocess, the child registers for "send me a SIGKILL
    when my parent terminates".
享受孤独 2024-07-15 19:30:14

orip 的答案很有帮助,但有一个缺点,它会终止您的进程并向您的父进程返回错误代码。 我这样避免了:

class CleanChildProcesses:
  def __enter__(self):
    os.setpgrp() # create new process group, become its leader
  def __exit__(self, type, value, traceback):
    try:
      os.killpg(0, signal.SIGINT) # kill all processes in my group
    except KeyboardInterrupt:
      # SIGINT is delievered to this process as well as the child processes.
      # Ignore it so that the existing exception, if any, is returned. This
      # leaves us with a clean exit code if there was no exception.
      pass

然后:

  with CleanChildProcesses():
    # Do your work here

当然你可以用 try/ except/finally 来做到这一点,但你必须分别处理异常和非异常情况。

orip's answer is helpful but has the downside that it kills your process and returns an error code your parent. I avoided that like this:

class CleanChildProcesses:
  def __enter__(self):
    os.setpgrp() # create new process group, become its leader
  def __exit__(self, type, value, traceback):
    try:
      os.killpg(0, signal.SIGINT) # kill all processes in my group
    except KeyboardInterrupt:
      # SIGINT is delievered to this process as well as the child processes.
      # Ignore it so that the existing exception, if any, is returned. This
      # leaves us with a clean exit code if there was no exception.
      pass

And then:

  with CleanChildProcesses():
    # Do your work here

Of course you can do this with try/except/finally but you have to handle the exceptional and non-exceptional cases separately.

白日梦 2024-07-15 19:30:14

我需要这个问题的一个小变体(清理子进程,但不退出Python程序本身),并且因为这里没有在其他答案中提到它:

p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), 15)

setsid将在新会话中运行该程序,从而为其及其子进程分配一个新的进程组。 因此,在其上调用 os.killpg 也不会关闭您自己的 python 进程。

I needed a small variation of this problem (cleaning up subprocesses, but without exiting the Python program itself), and since it's not mentioned here among the other answers:

p=subprocess.Popen(your_command, preexec_fn=os.setsid)
os.killpg(os.getpgid(p.pid), 15)

setsid will run the program in a new session, thus assigning a new process group to it and its children. calling os.killpg on it thus won't bring down your own python process also.

夜巴黎 2024-07-15 19:30:14

民意调查()

检查子进程是否已终止。
返回 returncode 属性。

poll( )

Check if child process has terminated.
Returns returncode attribute.

寂寞清仓 2024-07-15 19:30:14

Windows 的解决方案可能是使用 win32 job api,例如 如何我是否会自动销毁 Windows 中的子进程?

这是现有的 python 实现

https://gist。 github.com/ubershmekel/119697afba2eaecc6330

A solution for windows may be to use the win32 job api e.g. How do I automatically destroy child processes in Windows?

Here's an existing python implementation

https://gist.github.com/ubershmekel/119697afba2eaecc6330

岁吢 2024-07-15 19:30:14

有没有办法确保所有创建的子进程在Python程序退出时都死掉? 我所说的子流程是指使用 subprocess.Popen() 创建的流程。

您可能会违反封装并测试所有 Popen 进程是否已终止

subprocess._cleanup()
print subprocess._active == []

如果不是,我是否应该迭代所有发出的kills,然后kills -9? 有什么更干净的吗?

如果不出去杀死每个幸存者,就无法确保所有子进程都已死亡。 但如果你遇到这个问题,很可能是因为你有更深层次的设计问题。

Is there a way to ensure all created subprocess are dead at exit time of a Python program? By subprocess I mean those created with subprocess.Popen().

You could violate encapsulation and test that all Popen processes have terminated by doing

subprocess._cleanup()
print subprocess._active == []

If not, should I iterate over all of the issuing kills and then kills -9? anything cleaner?

You cannot ensure that all subprocesses are dead without going out and killing every survivor. But if you have this problem, it is probably because you have a deeper design problem.

心舞飞扬 2024-07-15 19:30:14

我实际上需要这样做,但它涉及运行远程命令。 我们希望能够通过关闭与服务器的连接来停止进程。 此外,例如,如果您正在 python repl 中运行,并且希望能够使用 Ctrl-C 退出,则可以选择作为前台运行。

import os, signal, time

class CleanChildProcesses:
    """
    with CleanChildProcesses():
        Do work here
    """
    def __init__(self, time_to_die=5, foreground=False):
        self.time_to_die = time_to_die  # how long to give children to die before SIGKILL
        self.foreground = foreground  # If user wants to receive Ctrl-C
        self.is_foreground = False
        self.SIGNALS = (signal.SIGHUP, signal.SIGTERM, signal.SIGABRT, signal.SIGALRM, signal.SIGPIPE)
        self.is_stopped = True  # only call stop once (catch signal xor exiting 'with')

    def _run_as_foreground(self):
        if not self.foreground:
            return False
        try:
            fd = os.open(os.ctermid(), os.O_RDWR)
        except OSError:
            # Happens if process not run from terminal (tty, pty)
            return False

        os.close(fd)
        return True

    def _signal_hdlr(self, sig, framte):
        self.__exit__(None, None, None)

    def start(self):
        self.is_stopped = False
        """
        When running out of remote shell, SIGHUP is only sent to the session
        leader normally, the remote shell, so we need to make sure we are sent 
        SIGHUP. This also allows us not to kill ourselves with SIGKILL.
        - A process group is called orphaned when the parent of every member is 
            either in the process group or outside the session. In particular, 
            the process group of the session leader is always orphaned.
        - If termination of a process causes a process group to become orphaned, 
            and some member is stopped, then all are sent first SIGHUP and then 
            SIGCONT.
        consider: prctl.set_pdeathsig(signal.SIGTERM)
        """
        self.childpid = os.fork()  # return 0 in the child branch, and the childpid in the parent branch
        if self.childpid == 0:
            try:
                os.setpgrp()  # create new process group, become its leader
                os.kill(os.getpid(), signal.SIGSTOP)  # child fork stops itself
            finally:
                os._exit(0)  # shut down without going to __exit__

        os.waitpid(self.childpid, os.WUNTRACED)  # wait until child stopped after it created the process group
        os.setpgid(0, self.childpid)  # join child's group

        if self._run_as_foreground():
            hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)  # ignore since would cause this process to stop
            self.controlling_terminal = os.open(os.ctermid(), os.O_RDWR)
            self.orig_fore_pg = os.tcgetpgrp(self.controlling_terminal)  # sends SIGTTOU to this process
            os.tcsetpgrp(self.controlling_terminal, self.childpid)
            signal.signal(signal.SIGTTOU, hdlr)
            self.is_foreground = True

        self.exit_signals = dict((s, signal.signal(s, self._signal_hdlr))
                                 for s in self.SIGNALS)                                     

    def stop(self):
        try:
            for s in self.SIGNALS:
                #don't get interrupted while cleaning everything up
                signal.signal(s, signal.SIG_IGN)

            self.is_stopped = True

            if self.is_foreground:
                os.tcsetpgrp(self.controlling_terminal, self.orig_fore_pg)
                os.close(self.controlling_terminal)
                self.is_foreground = False

            try:
                os.kill(self.childpid, signal.SIGCONT)
            except OSError:
                """
                can occur if process finished and one of:
                - was reaped by another process
                - if parent explicitly ignored SIGCHLD
                    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
                - parent has the SA_NOCLDWAIT flag set 
                """
                pass

            os.setpgrp()  # leave the child's process group so I won't get signals
            try:
                os.killpg(self.childpid, signal.SIGINT)
                time.sleep(self.time_to_die)  # let processes end gracefully
                os.killpg(self.childpid, signal.SIGKILL)  # In case process gets stuck while dying
                os.waitpid(self.childpid, 0)  # reap Zombie child process
            except OSError as e:
                pass
        finally:
            for s, hdlr in self.exit_signals.iteritems():
                signal.signal(s, hdlr)  # reset default handlers

    def __enter__(self):
        if self.is_stopped:
            self.start()

    def __exit__(self, exit_type, value, traceback):
        if not self.is_stopped:
            self.stop()

感谢马尔科姆·汉德利 (Malcolm Handley) 的初步设计。 在linux上使用python2.7完成。

I actually needed to do this, but it involved running remote commands. We wanted to be able to stop the processes by closing the connection to the server. Also, if, for example, you are running in the python repl, you can select to run as foreground if you want to be able to use Ctrl-C to exit.

import os, signal, time

class CleanChildProcesses:
    """
    with CleanChildProcesses():
        Do work here
    """
    def __init__(self, time_to_die=5, foreground=False):
        self.time_to_die = time_to_die  # how long to give children to die before SIGKILL
        self.foreground = foreground  # If user wants to receive Ctrl-C
        self.is_foreground = False
        self.SIGNALS = (signal.SIGHUP, signal.SIGTERM, signal.SIGABRT, signal.SIGALRM, signal.SIGPIPE)
        self.is_stopped = True  # only call stop once (catch signal xor exiting 'with')

    def _run_as_foreground(self):
        if not self.foreground:
            return False
        try:
            fd = os.open(os.ctermid(), os.O_RDWR)
        except OSError:
            # Happens if process not run from terminal (tty, pty)
            return False

        os.close(fd)
        return True

    def _signal_hdlr(self, sig, framte):
        self.__exit__(None, None, None)

    def start(self):
        self.is_stopped = False
        """
        When running out of remote shell, SIGHUP is only sent to the session
        leader normally, the remote shell, so we need to make sure we are sent 
        SIGHUP. This also allows us not to kill ourselves with SIGKILL.
        - A process group is called orphaned when the parent of every member is 
            either in the process group or outside the session. In particular, 
            the process group of the session leader is always orphaned.
        - If termination of a process causes a process group to become orphaned, 
            and some member is stopped, then all are sent first SIGHUP and then 
            SIGCONT.
        consider: prctl.set_pdeathsig(signal.SIGTERM)
        """
        self.childpid = os.fork()  # return 0 in the child branch, and the childpid in the parent branch
        if self.childpid == 0:
            try:
                os.setpgrp()  # create new process group, become its leader
                os.kill(os.getpid(), signal.SIGSTOP)  # child fork stops itself
            finally:
                os._exit(0)  # shut down without going to __exit__

        os.waitpid(self.childpid, os.WUNTRACED)  # wait until child stopped after it created the process group
        os.setpgid(0, self.childpid)  # join child's group

        if self._run_as_foreground():
            hdlr = signal.signal(signal.SIGTTOU, signal.SIG_IGN)  # ignore since would cause this process to stop
            self.controlling_terminal = os.open(os.ctermid(), os.O_RDWR)
            self.orig_fore_pg = os.tcgetpgrp(self.controlling_terminal)  # sends SIGTTOU to this process
            os.tcsetpgrp(self.controlling_terminal, self.childpid)
            signal.signal(signal.SIGTTOU, hdlr)
            self.is_foreground = True

        self.exit_signals = dict((s, signal.signal(s, self._signal_hdlr))
                                 for s in self.SIGNALS)                                     

    def stop(self):
        try:
            for s in self.SIGNALS:
                #don't get interrupted while cleaning everything up
                signal.signal(s, signal.SIG_IGN)

            self.is_stopped = True

            if self.is_foreground:
                os.tcsetpgrp(self.controlling_terminal, self.orig_fore_pg)
                os.close(self.controlling_terminal)
                self.is_foreground = False

            try:
                os.kill(self.childpid, signal.SIGCONT)
            except OSError:
                """
                can occur if process finished and one of:
                - was reaped by another process
                - if parent explicitly ignored SIGCHLD
                    signal.signal(signal.SIGCHLD, signal.SIG_IGN)
                - parent has the SA_NOCLDWAIT flag set 
                """
                pass

            os.setpgrp()  # leave the child's process group so I won't get signals
            try:
                os.killpg(self.childpid, signal.SIGINT)
                time.sleep(self.time_to_die)  # let processes end gracefully
                os.killpg(self.childpid, signal.SIGKILL)  # In case process gets stuck while dying
                os.waitpid(self.childpid, 0)  # reap Zombie child process
            except OSError as e:
                pass
        finally:
            for s, hdlr in self.exit_signals.iteritems():
                signal.signal(s, hdlr)  # reset default handlers

    def __enter__(self):
        if self.is_stopped:
            self.start()

    def __exit__(self, exit_type, value, traceback):
        if not self.is_stopped:
            self.stop()

Thanks to Malcolm Handley for the initial design. Done with python2.7 on linux.

洒一地阳光 2024-07-15 19:30:14

你可以尝试subalive,这是我为类似问题编写的一个包。 它通过 RPC 使用定期的活动 ping,当主站由于某种原因停止活动 ping 时,从属进程会自动终止。

https://github.com/waszil/subalive

主进程示例:

from subalive import SubAliveMaster

# start subprocess with alive keeping
SubAliveMaster(<path to your slave script>)

# do your stuff
# ...

从属子进程示例:

from subalive import SubAliveSlave

# start alive checking
SubAliveSlave()

# do your stuff
# ...

You can try subalive, a package I wrote for similar problem. It uses periodic alive ping via RPC, and the slave process automatically terminates when the master stops alive pings for some reason.

https://github.com/waszil/subalive

Example for master:

from subalive import SubAliveMaster

# start subprocess with alive keeping
SubAliveMaster(<path to your slave script>)

# do your stuff
# ...

Example for slave subprocess:

from subalive import SubAliveSlave

# start alive checking
SubAliveSlave()

# do your stuff
# ...
新人笑 2024-07-15 19:30:14

通过生成一个单独的进程来监督销毁,可以在 Windows 上获得更多保证。

import subprocess
import sys
import os

def terminate_process_on_exit(process):
    if sys.platform == "win32":
        try:
            # Or provide this script normally. 
            # Here just to make it somewhat self-contained.
            # see https://stackoverflow.com/a/22559493/3763139
            # see https://superuser.com/a/1299350/388191
            with open('.process_watchdog_helper.bat', 'x') as file:
                file.write(""":waitforpid
tasklist /nh /fi "pid eq %1" 2>nul | find "%1" >nul
if %ERRORLEVEL%==0 (
    timeout /t 5 /nobreak >nul
    goto :waitforpid
) else (
    wmic process where processid="%2" call terminate >nul
)""")
        except:
            pass
        
        # After this spawns we're pretty safe. There is a race, but we do what we can.
        subprocess.Popen(
            ['.process_watchdog_helper.bat', str(os.getpid()), str(process.pid)],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )

# example
class DummyProcess:
    def __init__(self, pid):
        self.pid = pid
set_terminate_when_this_process_dies(DummyProcess(7516))

It's possible to get some more guarantees on windows by spawning a separate process to oversee the destruction.

import subprocess
import sys
import os

def terminate_process_on_exit(process):
    if sys.platform == "win32":
        try:
            # Or provide this script normally. 
            # Here just to make it somewhat self-contained.
            # see https://stackoverflow.com/a/22559493/3763139
            # see https://superuser.com/a/1299350/388191
            with open('.process_watchdog_helper.bat', 'x') as file:
                file.write(""":waitforpid
tasklist /nh /fi "pid eq %1" 2>nul | find "%1" >nul
if %ERRORLEVEL%==0 (
    timeout /t 5 /nobreak >nul
    goto :waitforpid
) else (
    wmic process where processid="%2" call terminate >nul
)""")
        except:
            pass
        
        # After this spawns we're pretty safe. There is a race, but we do what we can.
        subprocess.Popen(
            ['.process_watchdog_helper.bat', str(os.getpid()), str(process.pid)],
            stdout=subprocess.DEVNULL,
            stderr=subprocess.DEVNULL
        )

# example
class DummyProcess:
    def __init__(self, pid):
        self.pid = pid
set_terminate_when_this_process_dies(DummyProcess(7516))
情泪▽动烟 2024-07-15 19:30:14

这就是我为我的 posix 应用程序所做的:

当您的应用程序存在时,调用此类的 Kill() 方法:
http://www.pixelbeat.org/libs/subProcess.py

此处使用示例:
http://code.google.com/p/ fslint/源/浏览/主干/fslint-gui#608

This is what I did for my posix app:

When your app exists call the kill() method of this class:
http://www.pixelbeat.org/libs/subProcess.py

Example use here:
http://code.google.com/p/fslint/source/browse/trunk/fslint-gui#608

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文