一个父进程创建多个子进程,有些需…

在Linux下我们可以用fork函数创建一个子进程,但是当我们需要在一个父进程下创建多个子进程时,有些需要注意的地方。假设我们用如下代码在一个父进程下创建两个子进程:
void main()
{
pid_t pid1, pid2;
pid1 = fork();
pid2 = fork();
if(pid1 == 0)
{
printf("This is the first child process!\n");
exit(0);
}

if(pid2 == 0)
{
printf("This is the second child process!\n");
sleep(2);
exit(0);
}

if(pid1 != 0 &&   pid2 != 0)
{
waitpid(pid1, NULL, 0);
waitpid(pid2, NULL, 0);
exit(0);
}
}
如果我们用这个方式来创建两个子进程,则会出现一系列问题
首先,你用ps aux命令,会发现一共有4个进程,其中3个子进程,多了一个
其次,你会发现用这种方式无法检测到信号(signal)

发生这些状况的主要原因是我们没有对进程ID进行判断。当我们在父进程创建一个子进程时,在内存中就会多出一个父进程的副本(完全一样的拷贝,包括代码段和数据段),但是两个进程都是从第一个fork后面开始执行的,所以如果后面直接出现第二个fork,则在父进程和子进程中都会再创建一个它们自己的子进程,这样就一共有4个进程了。
同样,如果我们用kill,signal函数来传递接受信号,也会出问题。比如子进程1发送一个INT信号,子进程2在接收到这个信号后,打印"hello, kaito",若用如下方式来:
if(pid1 == 0)
{
kill(pid2, SIGINT);
exit(0);
}

if(pid2 == 0)
{
signal(SIGINT, func);
pause();
exit(0);
}
则发送不了信号,因为在第一个if里面pid1 == 0,说明在子进程1里面,子进程1它按道理没有子进程了,哪来的pid2,所以kill发送当然会失败。

所以,我们在创建子进程之间一定要对当前进程进行判断,最好是只有在父进程里面,才创建子进程。则的如下代码
#include "klib.h"

void int_pro(int a)
{
printf("Hello, kaito!\n");
return ;
}

void main()
{
pid_t kpid1 = 0xffff, kpid2 = 0xffff, pro1 = 0, pro2 = 0;
if(kpid1 != 0 && kpid2 != 0)
{
kpid1 = fork();
}
if(kpid1 != 0 && kpid2 != 0)
{
kpid2 = fork();
}
if(kpid1 != 0 && kpid2 != 0)
{
pro1 = kpid1;
pro2 = kpid2;
waitpid(kpid1, NULL, 0);
waitpid(kpid2, NULL, 0);
exit(0);
}
if(kpid1 == 0)
{
char p[100];
printf("Please input something:");
scanf("%s", p);
kill(pro2, SIGINT);
exit(0);
}
if(kpid2 == 0)
{
signal(SIGINT, int_pro);
pause();
exit(0);
}
}

接下来,我又写了一个创建用户输入个数进程的
#include "klib.h"

void multi_pro(int n)
{
int i = 0, flag = ~0x0;
pid_t pid[n];
memset(pid, 1, sizeof(pid));
for(i = 0; i < n; i++)
{
if((pid[i] & flag) != 0)
{
pid[i] = fork();
flag &= pid[i];
}
}
for(i = 0; i < n; i++)
{
if(pid[i] == 0)
{
pause();
exit(0);
}
}
}

void main()
{
int n = 0;
while(1)
{
printf("Please input the number of processes that you want to create:");
scanf("%d", &n);
multi_pro(n);
}
}
通过在中断输入Ctrl + C则可以发送SIGINT信号,最后会删除所有创建的子进程。这里用的方法就是在父进程标记一个flag,且始终保持它不为0。在任意子进程创建时,及时更新flag的值,若在父进程中,相与得非0;在子进程中相与得0,则在if判断中加上flag标志就可以区分出当前位置是父进程还是子进程。

如果需要用到信号(signal)在两个子进程中进行信号传递,则可以事先在if判断外面定义一个pid_t类型的变量来保存各个子进程的pid,则可以用kill发送信号。

最后贴一个创建进程执行文件的操作(shell使用的基本方式,只不过这里没有用argc和argv)
#include "klib.h"
pid_t src_pid;

void create_pro(int a)
{
pid_t tmp_pro;
tmp_pro = fork();
if(tmp_pro == 0)
{
if(a == 1)
{
execv("./hello_kaito", NULL);
exit(0);
}
if(a == 2)
{
execv("./hello_lily", NULL);
exit(0);
}
}
else
{
wait(NULL);
}
}

void main()
{
int n;
pid_t pid;
src_pid = getpid();
while(1)
{
printf("[1]say hello to kaito\n");
printf("[2]say hello to Lily\n");
scanf("%d", &n);
if(n == 1)
create_pro(1);
if(n == 2)
create_pro(2);
}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值