如何获取在c程序中使用system()启动的进程的PID

时间:2017-07-27 10:43:25

标签: c linux pid

我在下面有一个脚本,用于指示将来自/dev/ttyUSB1的数据重定向到文件。

#!/bin/bash
# start minicom with file name of todays date
cat /dev/ttyUSB1 > ~/serial_logs/$1.txt &

我使用system()从c程序调用此脚本,该程序会创建一个包含当前日期和时间的文件。

//Get string with date & time
//Open minicom with logging to filename with date and time
strftime(s, sizeof(s), "%a%b%d%T", tm);
snprintf(buf, SM_BUF, "~/logging.sh %s",s);
system(buf); 

然而,在c程序的稍后时间我需要杀死这个过程。 System()不会返回cat进程的PID。

我遇到this post建议使用下面的功能,但我不清楚我是如何使用它的。

我的问题基本上是我作为参数传递给它的是什么?

pid_t system2(const char * command, int * infp, int * outfp)
{
    int p_stdin[2];
    int p_stdout[2];
    pid_t pid;

    if (pipe(p_stdin) == -1)
        return -1;

    if (pipe(p_stdout) == -1) {
        close(p_stdin[0]);
        close(p_stdin[1]);
        return -1;
    }

    pid = fork();

    if (pid < 0) {
        close(p_stdin[0]);
        close(p_stdin[1]);
        close(p_stdout[0]);
        close(p_stdout[1]);
        return pid;
    } else if (pid == 0) {
        close(p_stdin[1]);
        dup2(p_stdin[0], 0);
        close(p_stdout[0]);
        dup2(p_stdout[1], 1);
        dup2(::open("/dev/null", O_RDONLY), 2);
        /// Close all other descriptors for the safety sake.
        for (int i = 3; i < 4096; ++i)
            ::close(i);

        setsid();
        execl("/bin/sh", "sh", "-c", command, NULL);
        _exit(1);
    }

    close(p_stdin[0]);
    close(p_stdout[1]);

    if (infp == NULL) {
        close(p_stdin[1]);
    } else {
        *infp = p_stdin[1];
    }

    if (outfp == NULL) {
        close(p_stdout[0]);
    } else {
        *outfp = p_stdout[0];
    }

    return pid;
}

3 个答案:

答案 0 :(得分:1)

我将什么作为参数传递给它?

该函数接受指向整数(int*)的指针并写入这些整数地址,因此您需要有两个整数并传递它们的地址,如下所示:

int input, output; // input and output file descriptors
int pid = system2("script args", &input, &output);

答案 1 :(得分:1)

你对这个问题采取了错误的方法。

使用fork / exec和管道发布的示例代码是运行外部命令并读取其输出的正确方法。但是,您运行的命令是cat。所有这一切都是读取文件并输出。

因此,不要启动单独的流程来调用cat,只需打开文件并从中读取:

FILE *fp = fopen("/dev/ttyUSB1", "r");
if (!fp) {
    perror("open failed");
    exit(1);
} else {
    // read from file
    ...
}

答案 2 :(得分:0)

虽然您可以使用fork() / exec()启动外部命令(在获取PID时),如@dbush's answer所指出的那样,您需要的操作(从一个文件读取并写入到另一个)很简单,你可以在代码中做到这一点。但是,由于您希望它在后台运行,直到主代码决定停止它,您 仍然需要使用fork()。以下代码显示了基本概念:

#include <stdio.h>
#include <signal.h>

int main()
{
    // Prevent killed child-processes remaining as "defunct"
    struct sigaction sigchld_action = {
        .sa_handler = SIG_DFL,
        .sa_flags = SA_NOCLDWAIT
    };
    sigaction( SIGCHLD, &sigchld_action, NULL ) ;

    // Duplicate ("fork") the process. Will return zero in the child
    // process, and the child's PID in the parent (or negative on error).
    int pid = fork() ;
    if( pid < 0 ) {
        printf( "Fork failed\n" ) ;
        return 1 ;
    }

    if( pid == 0 ) {
        // ------------ Child process
        // Here is where you'd open "/dev/ttyUSB1" and the output file
        // and continually read data from one and write it to the other.
        while( 1 ) {
            printf( "child process\n" ) ;
            sleep(1) ;
        }
        return 0 ; //never reached
    }

    // ------------ Parent process
    // Here is where you'd do whatever the main program needs to do.
    printf( "Main program\n" ) ;
    sleep(10);

    // When you are ready, it can kill the child process
    printf( "Killing child\n" ) ;
    kill( pid, SIGTERM ) ;

    printf( "Finished\n" ) ;
    return 0 ;
}

读写的实际实现留给读者练习。

注意:如果代码顶部没有sigaction调用,子进程将保留为<defunct>进程,期望父进程等待它们完成,它可以检查他们的退出状态。在这种情况下,我们对任何返回代码都不感兴趣,所以我们让它们立即死亡。