【问题标题】:How to get the PID of a process that was started with system() in a c program如何在c程序中获取以system()启动的进程的PID
【发布时间】:2017-07-27 10:43:24
【问题描述】:

我在下面有一个脚本,它将来自/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;
}

【问题讨论】:

标签: c linux pid


【解决方案1】:

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

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

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

【讨论】:

    【解决方案2】:

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

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

    因此,与其启动一个单独的进程来调用cat,不如打开文件并从中读取:

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

    【讨论】:

    • 听起来 OP 希望读取(和写入文件)“在后台”发生,在未来的某个时候被杀死。因此,即使他们替换了cat 的使用,他们仍然需要在代码的forked 副本中进行读写操作。
    • 嗨@dbush,感谢您的有用评论。 @TripeHound 是的,我想要的是开始(仅)从串行端口读取到文件,然后稍后停止读取文件。因此,为了做到这一点,我需要知道 cat 进程的 PID,以便我可以使用 system()pkill 从 c 程序中杀死它。
    • @riverrock 我无法将任何代码放在一起,但您应该能够只使用fork 创建一个子进程(返回一个PID)而不是执行@ 987654331@,让它循环重复从 USB1 读取并写入文件。同时,父进程可以做它需要做的事情,并在需要时杀死子进程。
    【解决方案3】:

    虽然您可以使用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 调用,子进程将保持为 &lt;defunct&gt; 进程,期望父进程将等待它们完成,以便它可以检查它们退出状态。在这种情况下,我们对任何返回码都不感兴趣,所以我们让它们立即死亡。

    【讨论】:

      猜你喜欢
      • 2010-12-30
      • 2021-05-14
      • 2011-06-12
      • 2014-06-25
      • 2013-07-03
      • 2013-02-07
      • 1970-01-01
      • 2012-09-20
      相关资源
      最近更新 更多