2013-06-19 66 views
1

一样的问题说,我在Csubprocess.popen(蟒蛇)使用C

p = subprocess.Popen(cmd, shell=True, stdout=subprocess.PIPE, preexec_fn=os.setsid) 
print p.pid 

我试图生成一个进程,然后获取进程ID搜索的subprocess.open module

`cmd` is a c program that is spawned 

在C中,我相信getpid()完成这项工作。

但我产卵后,我不知道如何告诉getpid()得到那个衍生过程,PID。

void run_apps(pid) { 
     printf("process ID is %d\n", (int) getpid()); 
} 

这显然是给出当前进程ID。

+0

看到这个答案http://stackoverflow.com/questions/15274016/why-am-i-forking-more-than-5-times-here/15274727#15274727 – OregonTrail

+0

@OregonTrail:但你不主动新的外部过程还是你?我是C的初学者。 – pistal

+1

fork是生成进程的基础机制。它复制当前进程。 exec是你想要的,它复制当前进程然后用一个新的二进制可执行文件替换它 – OregonTrail

回答

1

在C中,通过首先调用fork()创建一个新进程(最终子进程),然后执行子进程的exec*()函数族之一,可以获得最大数量的选项。原始进程和新进程将同时运行,因此您可以通过管道或套接字对交换(读取和/或写入数据)。最后,使用例如waitpid()在一个循环中等待新进程退出,并“收获”其退出状态。例如:

#include <unistd.h> 
#include <sys/types.h> 
#include <sys/wait.h> 
#include <errno.h> 

int main(void) 
{ 
    pid_t child, p; 
    int status; 

    /* 
    * Prepare pipes et cetera first. 
    */ 

    /* Fork to create the subprocess. */ 
    child = fork(); 
    if (child == (pid_t)-1) { 
     /* Cannot fork(); usually out of resources (user limits). 
     * see errno for details. With <string.h>, you can use 
     * strerror(errno) to obtain the error string itself. */ 
     return 1; 

    } else 
    if (!child) { 
     /* This is the child process itself. 
     * Do whatever cleanup is necessary, then 
     * execute the subprocess command. */ 
     execlp("/bin/ls", "ls", "-lA", NULL); 

     /* This is only reached if the exec failed; 
     * again, see errno for reason. 
     * Always have the child process exit! */ 
     return 127; 
    } 

    /* This is only run by the parent process 
    * (because the child always exits within the 
    * else if body above). 
    * 
    * The subprocess PID is 'child'. 
    */ 

    /* Wait for the child process to exit. */ 
    do { 
     status = 0; 
     p = waitpid(child, &status, 0); 
     if (p == (pid_t)-1 && errno != EINTR) 
      break; /* Error */ 
    } while (p != child); 

    if (p != child) { 
     /* Child process was lost. 
     * If (p == (pid_t)-1), errno describes the error. 
     */ 

    } else 
    if (WIFEXITED(status)) { 
     /* Child process exited with WEXITSTATUS(status) status. 
     * A status of 0 (or EXIT_SUCCESS) means success, 
     * no errors occurred. Nonzero usually means an error, 
     * but codes vary from binary to binary. 
     */ 

    } else 
    if (WIFSIGNALED(status)) { 
     /* Child process died from WTERMSIG(status) signal. 
     * If you include <string.h>, you can use 
     *  strsignal(WTERMSIG(status)) 
     * to obtain the name (string) of the terminating signal. 
     */ 

    } else { 
     /* Child process died from unknown causes. 
     */ 

    } 

    /* All done. */ 
    return 0; 
} 

就个人而言,我更喜欢使用socketpair()创建经由pipe()创建我控制过程和管之间的Unix域流或数据报套接字如果子流程仅仅是一些随机二进制来运行。在所有情况下,您都可以使用dup2()函数,用套接字或管道替换标准输入(STDIN_FILENO描述符),标准输出(STDOUT_FILENO描述符)和标准错误(STDERR_FILENO描述符)。如果需要,您甚至可以从父级访问/proc/[child]/下的伪文件以观察子进程的状态。

取决于您需要如何与子流程进行通信 - 从/到文件的输入/输出?内存中的字符串?动态分配输出缓冲区 - 有很多变体。当需要精确控制和/或全双工(包括读取和写入)和/或异步通信时,通常会使用与上述类似的代码。

您可以在您最喜爱的搜索引擎中搜索"linux" "fork" "exec",以获得不同质量的示例。


如果你想要一个简单的解决方案,你只需要捕获命令的输出(不供给输入命令,或者提供从文件输入),你可以使用的

一些变种
#include <unistd.h> 
#include <stdio.h> 
#include <errno.h> 

int main(void) 
{ 
    FILE *sub; 
    pid_t subpid; 
    int status; 

    sub = popen("setsid /bin/sh -c 'echo $$ ; exec command args' </dev/null", "rb"); 
    if (!sub) { 
     /* popen() failed. */ 
     return 1; 
    } 

    /* Read the first line from sub. It contains the PID for the command. */ 
    { 
     char buffer[32], *line, dummy; 
     int value; 

     line = fgets(buffer, sizeof buffer, sub); 
     if (!line) { 
      /* setsid failed, or non-POSIXy system (Windows?) */ 
      pclose(sub); 
      return 1; 
     } 
     if (sscanf(line, "%d%c", &value, &dummy) != 1 || value < 2) { 
      /* Internal bug, or extra output? */ 
      pclose(sub); 
      return 1; 
     } 

     /* subpid is also the session ID and the process group ID, 
     * because it is the session leader. */ 
     subpid = value; 
    } 

    /* Read from sub using standard I/O, to capture command output. */ 

    /* After no more output to read from sub, reap the subprocess. */ 
    errno = 0; 
    do { 
     status = pclose(sub); 
    } while (status == -1 && errno == EINTR); 

    if (status) { 
     /* Problem: sub exited with nonzero exit status 'status', 
     * or if status == -1, some other error occurred. */ 

    } else { 
     /* Sub exited with success (zero exit status). */ 
    } 

    /* Done. */ 
    return 0; 
} 

在Linux中,popen()使用/bin/sh壳(按POSIX.1规范),我们可以使用setsid命令行实用程序来创建新的会话。在该命令中,echo $$是一个sh命令,它输出外壳PID,exec CMD...用该命令替换外壳;因此即使在命令执行之前,我们也可以获得命令的PID。

+0

我很抱歉删除了以前的评论,他们没有给出新过程的PID。 – pistal

+0

例如,我不能说“./mb 1”而不是“ls -la” – pistal

+1

@ user2015933:我不明白。我的第一个片段将会在'child'中创建新进程的pid,并在'subpid'中创建第二个片段。要执行'./mb 1',你可以使用例如'execl(“./ mb”,“./mb”,“1”,NULL);'在第一个片段中(第一个参数*是命令名称本身,这就是为什么它是“重复”;请参阅'man execl'手册页)。在第二个片段中,您可以使用'sub = popen(“setsid/bin/sh -c'echo $$; exec ./mb 1'