【问题标题】:Lost in Multiple Fork(), Pipe() and Select()迷失在多个 Fork()、Pipe() 和 Select() 中
【发布时间】:2026-01-18 16:50:02
【问题描述】:

希望我能在这里找到一些帮助,因为我开始放弃了。请注意,因为这是一项家庭作业,因此它可能很愚蠢。

上下文: 必须编写一些将被 shell 执行的东西:
logn [--tick n] cmd [args] [, cmd [args]]...

基本上是多个程序同时进行的程序。

约束: 每个输出行必须以它的命令号开头,格式为 printf "%d: %s" IE: 0:第一个命令的第一行。
0:第一个命令的第二行。
1:第二条命令的第一行。
0:第一个命令的第三行。
1:第二条命令的第二行。

如果已指定刻度,如果 n 秒内没有发送输出,系统将打印一个句点。
必须使用 Select()
如果最后输出的是句号,则系统不会打印另一个句号。

现在这是我的问题!我能够使用单个命令使其工作。当我尝试使其成为多个命令时,我似乎失败了。我相信这可能是我的方法。也许你们中的一些人可以帮助我。

这是我尝试的 Multiple Cmd。我可能完全错了,因此我需要帮助:

#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/time.h> 
#include "readline.h"

// Reference: http://www.gnu.org/s/libc/manual/html_node/Waiting-for-I_002fO.html
int input_timeout (int filedes, unsigned int seconds)
{
    fd_set set;
    struct timeval timeout;

    /* Initialize the file descriptor set. */
    FD_ZERO (&set);
    FD_SET (filedes, &set);

    /* Initialize the timeout data structure. */
    timeout.tv_sec = seconds;
    timeout.tv_usec = 0;

    /* select returns 0 if timeout, 1 if input available, -1 if error. */
    return (select (FD_SETSIZE,&set, NULL, NULL, &timeout));
}

/* Fetches the number of commands in parameters. Number of Commas + 1 */
int getNbCmd(char ** argv)
{
    int nbCmd = 1;
    int i;    
    while(argv[i] != '\0')
    {        
        if(strcmp(argv[i], ",") == 0)
            nbCmd++;
        i++;
    }

    return nbCmd;
}


/* Fills the Command Array */
void getCommandes(char *** tbCmd, int argc, char ** argv)
{    
    int indexArgv = 1;
    int indexCmd = 0;
    int indexTbCmd = 0;        

    char ** cmd = (char **)malloc(argc*sizeof(char *));

    if(strcmp(argv[indexArgv], "--tick") == 0)
        indexArgv = 3;

    while (indexArgv < argc)
    {

        if(strcmp(argv[indexArgv], ",") == 0)
        {    
            cmd[indexCmd] = (char *) 0;
            tbCmd[indexTbCmd] = cmd;
            free(cmd);
            cmd = (char **)malloc(argc*sizeof(char *));

            indexTbCmd++;
            indexCmd = 0;
        }
        else
        {
            char * arg;
            arg = argv[indexArgv];
            cmd[indexCmd] = arg;        

            indexCmd++;
        }
        indexArgv++;
    }

    cmd[indexCmd] = (char *) 0;
    tbCmd[indexTbCmd] = cmd;
    free(cmd);        
}


int main (int argc, char ** argv)
{
    int nbCmds = getNbCmd(argv);    
    int tick = -1;    

    char *** tbCmd = (char ***) malloc (nbCmds*sizeof(char **));

    if(strcmp(argv[1], "--tick") == 0)
        tick = atoi(argv[2]);

    getCommandes(tbCmd, argc, argv);

    int i;

    pid_t pidM[nbCmds];    
    int p[nbCmds][2];

    for (i = 0;i < nbCmds;i++)
    {            
        if ( pipe( p[i] ) != 0 ){ perror( "pipe()" ); exit(1); }

        // fork() to get child process        
        pidM[i] = fork();    

        if ( pidM[i] < 0 ){ perror( "fork()" ); exit(1); }
        else if (pidM[i] == 0)
        {
            close(p[i][0]);
            dup2(p[i][1], STDOUT_FILENO);    

            int ret;
            ret = execvp(tbCmd[i][0], tbCmd[i]);            
        }
        else
        {
            close(p[i][1]);

            char * buffer;
            int retval = 1;
            int pntAfficher = 0;  //Boolean for Period Printing
            /* select returns 0 if timeout, 1 if input available, -1 if error. */
            if(tick >= 0)
                retval = input_timeout(p[i][0], tick);
            if (retval == 0 && pntAfficher == 0)
            {
                printf(".\n");
                pntAfficher = 1;
            }

            buffer = readline(p[i][0]);
            while(buffer[0] != '\0')
            {                
                printf("%d: %s",i, buffer);
                free(buffer);

                /* select returns 0 if timeout, 1 if input available, -1 if error. */
                if(tick >= 0)
                    retval = input_timeout(p[i][0], tick);
                if (retval == 0 && pntAfficher == 0)
                {
                    printf(".\n");
                    pntAfficher = 1;
                }
                buffer = readline(p[i][0]);
                pntAfficher = 0;

            free(buffer);
            }
        }
    }
free(tbCmd);

}

【问题讨论】:

  • 与你的问题无关(我认为下面回答的人已经指出了这个问题),但你可能想考虑使用 poll() 而不是 select()。它有一个更好的接口,通常支持比 fd_set 更多的文件描述符。

标签: c select fork pipe


【解决方案1】:

您需要在一个循环中分叉所有子项,然后在第二个循环中,从所有子项中读取所有数据。

您想要并行收听所有孩子的输出(这是select 正在为您做的事情),但所有孩子都需要运行才能正常工作。您当前的 for 循环产生一个孩子,然后转到 select... 这不适合它。

【讨论】:

    【解决方案2】:

    不太清楚你说“似乎失败”是什么意思,但看起来你需要修改你的代码才能倾听你所有孩子的声音。可以用select来做,看看select的man,试试用FD_SET添加多个fd

    【讨论】:

      最近更新 更多