在挂起状态

时间:2018-04-24 13:22:56

标签: python

我可以在Python中创建一个子进程并暂停它:

proc = subprocess.pOpen(['binary', 'arg1', 'arg2'])
# Subprocess was created in a running state
proc_handle = psutil.Process(pid=proc.pid)
proc_handle.suspend()
# Subprocess is now suspended
proc_handle.resume()
# Subprocess is now running

问题:如何在暂停状态下启动子进程?我知道创建子进程和挂起它之间的时间很短,但我对无缝解决方案很感兴趣。此外,我知道我可以轻松地将子进程包装在父进程中,该进程将在继续之前等待恢复信号,但是如果存在的话,我想要一个不那么hacky,更优雅的解决方案。此外,我知道我可以创建一个围绕子进程的类包装器,它不会创建它直到我真的想要运行它,但后来我还没有为它分配一个PID而我赢了#39 ; t能够检查统计数据,例如未启动进程的内存占用情况。

如果我能做到这一点,我会很高兴:

cmd = ['binary', 'arg1', 'arg2']
proc = subprocess.pOpen(cmd, autostart=False) # autostart argument does not exist
# Subprocess was created, so it had a PID and has a memory footprint, 
# but is suspended and no code had been run

我在使用autostart = False编写上述pOpen示例时认识到,由于进程的运行方式,这可能无法实现。如果我想在main()函数的开头打破,那么一些代码将作为静态初始化的一部分执行。理想情况下,在创建和初始化进程内存之后,子进程将在该步骤之前暂停。

注意:我特别感兴趣的是在Linux环境中解决这个问题,但如果存在,那么独立于平台的解决方案就会很棒。

1 个答案:

答案 0 :(得分:2)

fork()之后exec()

之前停止

这个很容易,但不太有用:

import subprocess, os, signal
proc = subprocess.Popen(
    ['binary', 'arg1', 'arg2'],
    preexec_fn=lambda: os.kill(os.getpid(), signal.SIGSTOP),
)

为什么“不那么有用”?因为虽然preexec_fn在新PID中运行,但您的意图似乎涉及收集内存使用情况的统计信息(在程序执行malloc()调用之前可以完成的程度),直到exec发生,你将测量其内存的程序是Python解释器。

在调用exec()

之前main()之后停止

首先,为Linux加载程序(ld.so)编译审计模块,类似于以下内容:

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>

unsigned int la_version(unsigned int version) {
    return version;
}

/* To have stronger guarantees of immediacy, I might replace this with flock()ing a
 * lockfile, and releasing that lock from the parent when ready to continue. YMMV,
 * consider this a stub intended to be replaced.
 */
void la_preinit(uintptr_t *cookie) {
    kill(getpid(), SIGSTOP);
    unsetenv("LD_AUDIT");        /* avoid our children getting stopped the same way */
}

然后,在运行子进程时指定它:

newEnv = dict(os.environ)
newEnv['LD_AUDIT'] = '/path/to/above/library.so'
proc = subprocess.Popen(['binary', 'arg1', 'arg2'], env=newEnv)
la_preinit启动之前,

main()由加载程序调用。