一个进程 fork 多个子进程

本文详细阐述了如何通过多进程及线程实现复杂并发场景下的高效处理,包括避免高并发问题的方法、正确使用fork与线程的技术细节、文件追加操作的原子性以及多进程间的通信技巧。同时,文中通过实例代码展示了避免子进程无限递归的错误处理方式。

今天要做这么一件事情,一个主进程fork出N个子进程,然后主进程用roundrobin的策略通知各个子进程, 每通知一次,对应子进程就产生一个线程,去做一件事情。为啥要搞这么麻烦呢,主要是为了防止高并发的情况。其实用线程池应该可以搞定的,不过时间比较赶,能力不济,线程池实现进程来不及。而且一个进程,就算把线程的stack设小,最多也就1000多个线程吧, 多个进程就可以把 capacity 上升到10,000量级。 说穿了,还是为了防止高并发。

今天还学到 open 一个文件,加上 O_APPEND, 就是追加,而且是原子操作,以前前我多线程写文件还用了互斥锁,看来完全没有必要。

for (i = 0;  i < PROCESS_NUM ; i++)

  pid[i] = fork();  

我就SB西西的向上面这样写,然后就挂了,问题是出在:当 i =0; fork出第一个子进程,但是循环没结束,所以子进程,会继续fork自己的子进程。 程序就抽风了。

改成下面这样就OK了, 因为fork返回给child process 0,所以用 break 防止child process keep forking .

for(i = 0; i < PROCESS_NUM; i++)
{
  if(0 == (pid[i] = fork()))  

    break;   // for child process
}

全部的代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define SIZE    20
#define PROCESS_NUM 10 

int main(void)

{   

  int i;

  pid_t pid[PROCESS_NUM];

  int fd[PROCESS_NUM][2];

  for(i = 0; i < PROCESS_NUM; i++)

  {
        pid[i] = -1;
        pipe(fd[i]);
  }
   
  for(i = 0; i < PROCESS_NUM; i++)
  {
        if(0 == (pid[i] = fork()))
          break;   // for child process

  }
   
  for(i = 0; i < PROCESS_NUM; i++)

  {

    if(0 == pid[i])
           {
             close(fd[i][1]);


           //child process add here
                child(i, fd[i][0]);
       return 0;

    }

  }

     //father process

  for(i = 0 ; i < PROCESS_NUM; i++)

    close(fd[i][0]);

  for(i = 0; i < PROCESS_NUM; i++)

    notify_child(i, fd[i][1], 'a');

  for(i = 0; i < PROCESS_NUM; i++)

    notify_child(i, fd[i][1], 'q');  

  wait(NULL);
  return 0;
}

child 和 notify_child就是简单的管道的读写操作,因为默认read pipe 是阻塞的,所以可以用作消息通知。

void child(int i, int readfd)

{

  char flag;

  while(1)

  {

    read(readfd, &flag, 1);

    if(flag == 'q')

      break;  

    else

      //to do .....

  }

}

void notify_child(int i, int writefd, chat flag)

{

      write(writefd, &flag, 1);

}

转载于:https://www.cnblogs.com/junli/archive/2011/07/07/2099725.html

### 创建个子进程的方法及实现细节 在 Linux 中,`fork()` 函数是一个常用工具用于创建新进程。当调用 `fork()` 时,它会复制当前进程并生成一个新的子进程[^2]。父进程和子进程的区别在于 `fork()` 的返回值:对于子进程而言,`fork()` 返回 0;而对于父进程来说,`fork()` 返回的是子进程的 PID。 为了创建个子进程,可以次调用 `fork()` 函数。每次调用都会生成一个新的子进程,并且这些子进程都可以独立运行自己的代码逻辑。以下是具体的实现方法: #### 方法一:循环调用 `fork()` 通过在一个循环中反复调用 `fork()` 可以轻松地创建个子进程。需要注意的是,在每次调用之后要检查返回值以区分父进程和子进程的行为。 ```c #include <stdio.h> #include <unistd.h> int main() { int num_processes = 5; // 假设我们要创建5个子进程 pid_t pid; for (int i = 0; i < num_processes; ++i) { pid = fork(); if (pid == 0) { // 子进程 printf("Child %d with PID: %d\n", i + 1, getpid()); break; // 每个子进程只执行一次就退出循环 } else if (pid > 0) { // 父进程 continue; } else { // 错误处理 perror("Fork failed"); return 1; } } if (pid != 0) { // 如果不是子进程,则是父进程 sleep(1); // 让父进程稍作等待以便观察输出 printf("Parent process with PID: %d\n", getpid()); } return 0; } ``` 上述程序展示了如何利用简单的循环结构来创建指定数量的子进程。注意这里使用了 `break` 来确保每个子进程仅打印一条消息后立即结束其自身的循环部分。 #### 方法二:递归调用 `fork()` 另一种方式是采用递归来不断分裂新的子进程直到达到预定的数量为止。这种方法虽然可行但通常不推荐因为容易造成资源浪费以及难以控制最终产生的总进程数。 ```c void create_children(int n) { if (n <= 0 || fork() != 0) return; // Base case or parent branch printf("New child created by PID:%d\n", getpid()); --n; create_children(n); } int main(){ const int NUM_CHILDREN = 3; create_children(NUM_CHILDREN); if(fork()!=0){ printf("I am the original Parent Process ID :%d \n",getpid()); } return 0; } ``` 此示例中的函数 `create_children` 使用递归形式每层减少所需创建的孩子数目直至零停止进一步分叉。 #### 实现注意事项 - **同步机制**:由于所有进程都是并发运行的,因此可能需要某种形式的同步原语(如信号量、互斥锁等),以防数据竞争条件发生。 - **僵尸进程清理**:每当一个进程终止而未被回收前,它的状态信息仍然保存于内存之中成为所谓的“僵尸”。为了避免这种情况,应该让父进程适时调用 `wait()` 或者 `waitpid()` 收集已死掉孩子的退出码[^1]。 - **错误检测**:始终验证 `fork()` 调用的结果是否失败 (`< 0`) 并采取适当措施响应异常状况。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值