【问题标题】:Pipes between child processes子进程之间的管道
【发布时间】:2014-05-05 21:38:08
【问题描述】:

我编写了一个 C 程序,它应该创建一定数量的子进程,每个子进程必须从字符串中更改 1 个字母。从键盘读取字符串和子进程数。

我想用管道来做。它应该是这样工作的:父母改变一个字母,然后第一个孩子接受父母修改的字符串并再改变一个字母。第二个孩子接受第一个孩子修改的字符串(2个字母已经改变)并再改变一个,依此类推。我是 C 新手,不太确定它是如何工作的,尤其是管道。

孩子们也可以通过管道在他们之间链接,或者他们只能链接到父母,它必须是这样的:第一个孩子改变一个字母,把字符串还给父母,然后第二个孩子从那里读取,修改字母并回馈。 如果是这样,有什么方法可以确保不会发生这种情况:Apples 变成 AppleD,然后 AppleX,然后 AppleQ?

例如:

input:

3 Apples  

output:

Applex Appldx Apqldx

我的问题是:我没有从孩子们那里得到任何输出。不确定我做错了什么。非常感谢您的帮助,在此先感谢!

这是我的代码:

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

void error(char* msg)
   {
   fprintf(stderr, "%s\n", msg);
   exit(1);
   }

char* modify(char msg[])
   {
   srand(time(NULL));
   int pos1=rand()%((int)strlen(msg));
   srand(time(NULL));
   int pos2=rand()%26;
   srand(time(NULL));
   int big=rand()%2;
   if(big==1) 
      {
      msg[pos1]=(char)(((int)'A')+pos2);
      }
   else 
      {
      msg[pos1]=(char)(((int)'a')+pos2);
      }

   return msg;
   }

int main(int argc, char *argv[])
   {
   if(argc!=3) 
      {
      error("Wrong number of arguments\n");
      }

   int nrch;
   nrch=atoi(argv[1]);
   char* msg=argv[2];

   printf("Parent: erhalten: %s\n", msg);
   int i=0;
   msg=modify(argv[2]);
   printf("Parent: weiter: %s\n", msg);
   pid_t pids[10];
   int fd[2];

   if(pipe(fd) == -1) 
       {
       error("Can't create the pipe");
       }

   dup2(fd[1], 1);
   close(fd[0]);
   fprintf(stdout, msg);

   /* Start children. */
   for (i = 0; i < nrch; ++i) 
       {
       if ((pids[i] = fork()) < 0) 
          {
          error("Can't fork process");
          } 
       else if (pids[i] == 0) 
          {
          dup2(fd[0], 0);
          close(fd[1]);
          fgets(msg,255,stdin);
          printf("child%d: erhalten: %s\n", (i+1), msg);
          modify(msg);
          printf("child%d: weiter: %s\n", (i+1), msg);
          if (pipe(fd) == -1) 
             {
             error("Can’t create the pipe");
             }

          fprintf(stdout, msg);
          dup2(fd[1], 1);
          close(fd[0]);
          exit(0);
          }
       }

   /* Wait for children to exit. */
   int status;
   pid_t pid;
   while (nrch > 0) 
      {
      pid = wait(&status);
      printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
      --nrch; 
      } 
   }

【问题讨论】:

  • 我在您的代码中看不到任何“管道”。对我来说看起来像一个普通的函数。
  • 请注意,多次调用srand() 会破坏目的。事实上,它实际上保证了对rand() 的每次调用都返回相同的值,因为您不断将随机种子重置为相同的值(因为现代计算机速度很快,time() 每秒只更改它报告的值)。跨度>

标签: c string pointers pipe child-process


【解决方案1】:

您看不到孩子的输出的一个原因是您将他们的标准输出连接到管道的写入端,因此当他们写入标准输出时,它进入管道,而不是屏幕(或您发送的任何地方程序的标准输出到原来的)。

如果孩子不会执行需要标准输入和标准输出到管道的程序,则不要使用 I/O 重定向。只需在管道的正确端写入和读取即可。

如果您有多个子进程,您可能需要为每个子进程创建一个管道,但父进程将需要进行创建。您的代码在孩子中创建了一个管道;那根管子没用,因为只有孩子知道。您可能可以用一个管道完成所有操作,但不确定孩子将按哪个顺序运行。如果确定性很重要,请使用多个 pipe() 调用,至少两倍的 close() 调用。

单管解决方案

#include <assert.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/wait.h>
#include <time.h>
#include <unistd.h>

static void error(const char *fmt, ...)
{
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
    putc('\n', stderr);
    exit(1);
}

static void modify(char msg[])
{
    int pos1 = rand() % ((int)strlen(msg));
    int pos2 = rand() % 26;
    int big = rand() % 2;
    if (big == 1)
        msg[pos1] = (char)(((int)'A') + pos2);
    else
        msg[pos1] = (char)(((int)'a') + pos2);
}

static int read_pipe(int fd, char *buffer, size_t buflen)
{
    int nbytes = read(fd, buffer, buflen);
    if (nbytes <= 0)
        error("Unexpected EOF or error reading pipe");
    assert((size_t)nbytes < buflen);
    buffer[nbytes] = '\0';
    return nbytes;
}

int main(int argc, char *argv[])
{
    if (argc != 3)
        error("Usage: %s number 'message'", argv[0]);
    srand(time(NULL));

    int nrch = atoi(argv[1]);
    char *msg = argv[2];
    size_t len = strlen(msg);

    printf("Parent: erhalten: %s\n", msg);
    modify(msg);
    printf("Parent: weiter: %s\n", msg);

    int fd[2];

    if (pipe(fd) == -1)
        error("Can't create the pipe");

    if (write(fd[1], msg, len) != (ssize_t)len)
        error("Failed to write to pipe");

    /* Start children. */
    for (int i = 0; i < nrch; ++i)
    {
        int pid;
        if ((pid = fork()) < 0)
            error("Can't fork process");
        else if (pid == 0)
        {
            char buffer[255];
            int nbytes = read_pipe(fd[0], buffer, sizeof(buffer));
            printf("child%d: erhalten (%d): %s\n", (i + 1), nbytes, buffer);
            modify(buffer);
            printf("child%d: weiter (%d): %s\n", (i + 1), nbytes, buffer);
            write(fd[1], buffer, nbytes);
            exit(0);
        }
        else
            printf("Random: %d\n", rand());
    }

    /* Wait for children to exit. */
    while (nrch > 0)
    {
        int status;
        pid_t pid = wait(&status);
        printf("Child with PID %ld exited with status 0x%.4X.\n", (long)pid, status);
        --nrch;
    }

    char buffer[255];
    int nbytes = read_pipe(fd[0], buffer, sizeof(buffer));

    printf("Parent: weiter (%d): %s\n", nbytes, buffer);
    return 0;
}

示例输出

文件p1.c中的代码:

$ make p1 && ./p1 4 "Absolutely nothing to do with me"
gcc -O3 -g -std=c11 -Wall -Wextra -Wmissing-prototypes -Wstrict-prototypes -Wold-style-definition -Werror p1.c -o p1
Parent: erhalten: Absolutely nothing to do with me
Parent: weiter: AbsolutEly nothing to do with me
Random: 1120753102
child1: erhalten (32): AbsolutEly nothing to do with me
Random: 918317477
child1: weiter (32): AbsolutEly notzing to do with me
child2: erhalten (32): AbsolutEly notzing to do with me
child2: weiter (32): AbsolwtEly notzing to do with me
Random: 196864950
child3: erhalten (32): AbsolwtEly notzing to do with me
child3: weiter (32): AbsolwtEly notzing to ao with me
Random: 1584398270
Child with PID 42928 exited with status 0x0000.
Child with PID 42927 exited with status 0x0000.
Child with PID 42926 exited with status 0x0000.
child4: erhalten (32): AbsolwtEly notzing to ao with me
child4: weiter (32): AbsolwtEly notzing to ao with Ue
Child with PID 42929 exited with status 0x0000.
Parent: weiter (32): AbsolwtEly notzing to ao with Ue
$

注意循环中rand() 的杂散使用。它确保孩子们在消息中更改不同的字母。否则,它们最终都会在消息中的相同“随机”位置更改相同的“随机”字母。

您可以根据需要创建多管道解决方案。我从单管解决方案中得到了似乎是确定性的行为,尽管不能保证排序。例如,如果每个孩子使用nanosleep() 或等效项等待随机延迟:

            struct timespec nap = { .tv_sec = 0, .tv_nsec = (rand() % 1000) * 1000000 };
            nanosleep(&nap, 0);

然后你在子处理中得到一个任意序列。例如:

Parent: erhalten: Absolutely nothing to do with me
Parent: weiter: Absolutely nothinglto do with me
Random: 2028074573
Random: 988903227
Random: 1120592056
Random: 359101002
child4: erhalten (32): Absolutely nothinglto do with me
child4: weiter (32): vbsolutely nothinglto do with me
Child with PID 43008 exited with status 0x0000.
child3: erhalten (32): vbsolutely nothinglto do with me
child3: weiter (32): vbsolutelyGnothinglto do with me
Child with PID 43007 exited with status 0x0000.
child2: erhalten (32): vbsolutelyGnothinglto do with me
child2: weiter (32): vbsolutelyGnothinglto doawith me
Child with PID 43006 exited with status 0x0000.
child1: erhalten (32): vbsolutelyGnothinglto doawith me
child1: weiter (32): vbsolutelyGnothinglto doawimh me
Child with PID 43005 exited with status 0x0000.
Parent: weiter (32): vbsolutelyGnothinglto doawimh me

【讨论】:

  • 不要更改erhaltenweiter。这些词的意思并不重要——它们在问题中,对提问者的尊重意味着它们留在答案中。它们彼此不同;它们明确地标记了之前和之后的状态。它们的存在不应该比使用变量名(如 nrchpidsargv 更难理解)更难理解。掌握现实,你们只会说英语!
【解决方案2】:

尝试将您的代码更改为以下内容,不确定这是否正是您想要的。 反正孩子们都在跑……

int main(int argc, char *argv[])
{
    if (argc != 3)
    {
        error("Wrong number of arguments\n");
    }
    int nrch;
    nrch = atoi(argv[1]);
    char *msg = argv[2];

    printf("Parent: erhalten: %s\n", msg);
    int i = 0;
    msg = modify(argv[2]);
    printf("Parent: weiter: %s\n", msg);
    pid_t pids[10];
    int fd[2];
    /* Start children. */
    for (i = 0; i < nrch; ++i)
    {
        if ((pids[i] = fork()) < 0)
        {
            error("Can't fork process");
        }
        if (pipe(fd) == -1)
        {
            error("Can't create the pipe");
        }
        //    printf ( "  pids[i] %d , i %d \n", pids[i] , i);
        if (pids[i] == 0)
        {
            if (dup2(fd[0], 0) == -1)
            {
                error("Can't dup2 (A)");
            }
            close(fd[1]);
            fgets(msg, 255, stdin);
            printf("child%d: erhalten: %s\n", (i + 1), msg);
            modify(msg);
            printf("child%d: weiter: %s\n", (i + 1), msg);

            fprintf(stdout, msg);
        }
        else
        {
            // printf("in else i= %d \n",i);
            if (dup2(fd[1], 0) == -1)
            {
                error("Can't dup2 (B)");
            }
            close(fd[0])
            exit(0);
        }
    }

    /* Wait for children to exit. */
    int status;
    pid_t pid;
    while (nrch > 0)
    {
        pid = wait(&status);
        if (pid > -1)
            printf("Child with PID %ld exited with status 0x%x.\n", (long)pid, status);
        --nrch;
    }
    return 0;
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-09-02
    • 2014-06-20
    • 1970-01-01
    • 2019-02-27
    • 1970-01-01
    相关资源
    最近更新 更多