【问题标题】:Theory,Processes fork()理论,进程 fork()
【发布时间】:2013-12-04 12:03:37
【问题描述】:

早上好,我想问两件事.. 1)什么返回 fork() 对已经有 pid==0 的孩子做了什么?如果我继续分叉每个儿子,他们每个人的 pid 都将是 0 ??或不 ? 2) 这是我的文件 Buffer.c,它在单个进程上运行。 一开始它 forks() 出一些生产者(生产者)和一些消费者消费(),但恐怕每个生产者都进入下一个 cicle 并开始生产自己的其他消费者!因为它写 pid=-1 所以... 我希望这段代码只产生 P 生产者和 C 消费者,但我需要知道为什么每个生产者不创建其他消费者! 你能帮我吗,也许给我一个计划,我将用这段代码创建多少个进程? 也许做一个这样的计划:

父亲: 8 家生产商 - - - ... 他们每个人生产:5个消费者 等等等等……

int main(int argc, char **argv) {
  /....

  pid_t pid;
  pid_t cons_pid[C];


  /* fork producers */
  pid = -1;
  for(i=0; i<P && pid!=0; i++)
    pid=fork();

  switch(pid) {
  case -1:
    ...
  case 0:
    /* GENERIC PRODUCER i */
   ...
    /* PRODUCE() */
    printf("Producer %d exits\n",i);
  ...
    return 0;
  }

  /* fork consumers */
  pid = -1;
  for (j=0; j<C && pid!=0; j++)
    pid = cons_pid[j] = fork();

  switch(pid) {
  case -1:
    ....error
  case 0:
    /* GENERIC CONSUMER j */
    CONSUME()....
    }
    return 0;
  }

【问题讨论】:

  • 你读过fork、exec、PID、PPID等吗?作业?
  • 有人可以创建一个家庭作业标签吗!!!
  • 不允许使用作业标签 ;-)
  • 我读到过,但恐怕每个生产者也会 fork() 一些消费者,对吧?你同意还是不同意?

标签: c linux process


【解决方案1】:

在已经有 pid==0 的孩子身上返回一个 fork() 所做的事情

0 不是有效的 PID,因此根据定义,不可能有 PID=0 的进程,因此 PID=0 是一个完美定义的返回,用于指示子状态。

如果我继续分叉每个儿子,他们每个人的 pid 都将是 0

没有进程的 PID=0。所有 PID 都大于零!零只是新分叉的进程收到的返回值,表示它是子进程。使用子进程的getpid 函数查询子进程获得的实际PID。但是父进程不能执行这样的查询,因为在fork 和假定的查询函数调用之间的时间里,子进程可能已经终止(竞争条件)。所以你想让fork直接把PID返回给父级。

顺便说一句:术语是 parentchild 而不是 fatherson(过程是事物而不是人,尽管 TRON 电影描绘了什么)。

关于您的代码 sn-p:switch 语句在这里是错误的选择。您想使用if 语句。

【讨论】:

  • 谢谢,但在这种情况下,恐怕每个生产者也会 fork() 一些消费者,对吧?你同意不同意? (这段代码应该是正确的,是高手做的)
  • @user2993592:好吧,如果 fork 的返回值为 0,则该进程是子进程,应该避免分叉其他任何东西。所以 0==fork() 路径会阻止消费者进程分叉的发生。在您的情况下,它是生产者 pid==0 分支中的 return 语句。该返回将在生产者进程到达消费者分叉之前终止生产者进程。
【解决方案2】:

fork() 将当前进程拆分为父进程和子进程。孩子将有一个新的 PID,父亲保留旧的 PID。在两个进程中fork() 在拆分后返回。在父亲中,返回值将是孩子的 PID(使其知道),在孩子中,返回值为 0。

【讨论】:

  • 谢谢,但在这种情况下,恐怕每个生产者也会 fork() 一些消费者,对吧?你同意不同意? (这段代码应该是正确的,是高手做的)
【解决方案3】:

1) 可能的最低进程 ID 为 1,这是所有其他进程派生出来的 init 进程的 ID。因此,子进程或您的父进程不可能“已经拥有 ID 0”。您孩子的进程 ID必然大于 1。因此,您担心的问题不会发生。

2) 您所说的混淆是fork(返回两次,一次为父级,一次为新创建的子级!)的原因一个有点“奇怪”的返回值,它可以有这么多不同的值:

  • 可能是-1,然后出了点问题,没有创建子节点
  • 可以是正值,则你在父进程中,该值为子进程ID。就好像您调用了任何其他刚刚正常返回的“正常”函数。
  • 可以是0,那么你的代码就知道它现在在子进程中运行

你必须检查返回值 (if()),这样你才能知道你在哪个进程中。然后你描述的事情就不会发生(或者,应该发生,这假设你的代码没有任何错误)。

编辑:
代码可以稍微重写一下,这样它就摆脱了循环内的&amp;&amp; pid!=0,因此整体看起来不那么可怕:

int main()
{
    int pid, i;
    pid_t cons_pid[C];

    for(int i=0; i<P; ++i)
    {
        pid=fork();
        if(pid == -1) exit(1); /* fork error */
        if(pid ==  0) { producer(); return 0; }
    }
    for(i=0; i<C; ++i)
    {
        pid = fork();
        if(pid == -1) /* fork error */
            { /* should do a kill_producers(); here */ exit(2); }
        else if(pid ==  0) /* consumer */
            { consumer(); return 0; }
        else /* master process, remember all consumer pids */
            { cons_pid[j] = pid; }
    }
    /* ... */
    return 0;
}

【讨论】:

  • 谢谢,但在这种情况下,恐怕每个生产者也会 fork() 一些消费者,对吧?你同意不同意? (这段代码应该是正确的,是高手做的)
  • 代码看起来“有点奇怪”,但完全正确,它应该可以按预期工作。它创建P 子进程作为生产者并退出,单个父进程继续,然后再次创建C 子进程(作为消费者并退出)。如果if 子句在分叉循环中,代码会更容易理解,那么循环的测试条件会更容易一些(在这种情况下不需要为子进程中断循环),但在功能上是一样的。生产者通过return 0; 退出,因此他们不会创建任何消费者。
  • 唯一可能无法按预期工作的是存储消费者 pid。我不确定您想要实现什么,但实际上,您将每个消费者的 pid 存储在父进程的数组中,并且部分存储在消费者拥有的数组中。您可能只在父进程中使用它们。见编辑。
  • 谢谢你!我注意到了回报!所以没问题!!
猜你喜欢
  • 1970-01-01
  • 2023-03-25
  • 2011-06-27
  • 1970-01-01
  • 2010-12-29
  • 1970-01-01
  • 2017-06-27
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多