使用管道进行通信
编写程序建立一个无名管道,然后生成3个子进程,使这4个进程利用同一个管道进行通信。分别试验3写1读、2写2读情况,多次执行,看结果是否一致,并对记录的执行结果进行解释。
【注】没有关于管道的示例程序(因为比较简单),在多端写入时应该使用lockf加锁。
一》3写1读
代码如下:
#include
#include
#include
int pid[3];
int main(void)
{
int
fd[2];
char
outpipe[100],inpipe[100];//暂存读出,或要写入的字符串
pipe(fd);
int i;
for(i=0;i<3;i++)
{
pid[i]=fork( );
if(pid[i]==0)
break;
}
if(pid[1]==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 1 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
if(pid[2]==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 2 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
if(pid[3]=
=0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 3 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);//释放
exit(0);
}
wait(0);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
return
0;
}
运行结果:
第一次运行:
child 1 process is sending message!
child 2 process is sending message!
child 3 process is sending message!
第十五次:
child 1 process is sending message!
child 3 process is sending message!
child 2 process is sending message!
…….
(注释:因运行结果受父进程创建子进程的先后顺序影响,一般看到的结果是123,但是理论上,123,321,213等等的运行结果是会出现的,可以通过在分支前加sleep(5),来观察)
分析:
通过for(i=0;i<3;i++)
{
pid[i]=fork( );
if(pid[i]==0)
break;
}
可以实现父进程创建3个子进程,同时也避免了子进程再次创建子进程。
为了用wait()实现3个子进程先向管道里写入信息,然后父进程再读取。
子进程被创建后,争夺管道资源,当一个子进程抢到管道时,对其进行加锁,然后向管道里写入数据,之后解锁释放管道资源和cpu,之后父进程wait()操作。则剩下的两个子进程再争夺管道资源,直到都写入信息并父进程读出为止。
补:可见:多次执行,看结果是否一致
分析:
/============== 规定了子进程的运行顺序 ==============================
#include
#include
#include
int pid1,pid2,pid3;
int main(void)
{
int
fd[2];
char
outpipe[100],inpipe[100]; //暂存读出,或要写入的字符串
pipe(fd);
//创建子进程
while
((pid1=fork( ))= =-1);
if(pid1==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 1 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
}
else
{
while((pid2=fork( ))= =-1);
if(pid2==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 2 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
}
else
{
while((pid3=fork( ))= =-1);
if(pid3= =0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 3 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);//释放
}
else
{
wait(0);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
read(fd[0],inpipe,50);
printf("%s/n",inpipe);
}
}
}
return
0;
}
二》2写2读
#include
#include
#include
int pid[3];
int main(void)
{
int fd[2],
i;
char
outpipe[100],inpipe[100];//暂存读出,或要写入的字符串
pipe(fd);
for(i=0;i<3;i++)
{
pid[i]=fork( );
if(pid[i]==0)
break;
}
if(pid[1]==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 1 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
if(pid[2]==0)
{
lockf(fd[1],1,0);
sprintf(outpipe,"child 2 process is sending message!");
write(fd[1],outpipe,50);
sleep(5);
lockf(fd[1],0,0);
exit(0);
}
if(pid[3]==0)
{
lockf(fd[0],1,0);
read(fd[0],inpipe,50);
printf("Child 3 read:n%s/n",inpipe);
lockf(fd[0],0,0);//释放
exit(0);
}
wait(0);
read(fd[0],inpipe,50);
printf("Parent read:n%s/n",inpipe);
exit(0);
}
运行结果:
Child 3 read:
Child 1 process is sending message!
Parent read:
Child 2 process is sending message!
(注释:因运行结果受父进程创建子进程的先后顺序影响,一般看到的结果如上,但是理论上,
Child 3 read:
Child 2 process if sending message!
Parent read:
Child 1 process is sending message!
等其他运行结果是会出现的。而且读不到的情况也有可能出现,比如先创建子进程1,若设1为读。当1被创建后,1抢到了管道资源并给予加锁,但此时管道中无可读数据,1执行sleep()释放cup,父进程得到cup创建过子进程2,3,2,3因得不到管道资源无法向管道中写入数据,则1占用管道但无法从管道中读出数据,父进程又等子进程先执行玩。此时,就发生了死锁。
)
结果分析:
通过for(i=0;i<3;i++)
{
pid[i]=fork( );
if(pid[i]==0)
break;
}
可以实现父进程创建3个子进程,同时也避免了子进程再次创建子进程。子进程1,2向管道中写入数据,子进程3和父进程从管道中读出数据并输出。
为了用wait()实现3个子进程先执行,1、2抢占管道资源并向管道中写入信息,然后父进程和子进程3从管道中读出信息并输出。
子进程被创建后,父进程再次执行wait()操作让子进程先执行,三个子进程争夺管道资源,当子进程1抢到管道时,对其进行加锁,然后向管道里写入数据,之后解锁释放管道资源和cpu,子进程3获得cup和管道后,从管道中读出数据并输出。子进程1抢到管道时,对其进行加锁,然后向管道里写入数据,之后解锁释放管道资源和cpu。子进程执行完,父进程获得cup和管道后,从管道中读出数据。