Linux系统编程--进程间通信 ---管道篇
Posted 蚍蜉撼树谈何易
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux系统编程--进程间通信 ---管道篇相关的知识,希望对你有一定的参考价值。
进程间通信
进程间通信
进程间通信的定义
进程间通信就是在不同进程之间传播或交换信息
进程间通信的目的
数据传输:一个进程需要将它的数据发送给另一个进程
资源共享:多个进程之间共享同样的资源。
通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)。
进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变。
进程间通信的发展。
管道
System V进程间通信
POSIX进程间通信
进程间通信的分类
管道
匿名管道pipe
命名管道
System V IPC
System V 消息队列
System V 共享内存
System V 信号量
POSIX IPC
消息队列
共享内存
信号量
互斥量
条件变量
读写锁
进程通信的方式及原理介绍
管道
管道是Unix中最古老的进程间通信的形式。
我们把从一个进程连接到另一个进程的一个数据流称为一个“管道”
管道分类:
匿名管道和命名管道
匿名管道
匿名管道的创建
int pipe(fd[2]);
头文件#include<unistd.h>
返回值: 0代表成功创建,-1代表管道创建失败
参数为输出型参数,其中数组第一个元素为读端,第二个为写入端。
匿名管道的特性:
1.管道是半双工的,只能一端写,一端读。
2.匿名管道创建出来的话是没有标识符的,导致了其他进程无法查询到此缓冲区。但是创建的进程可以通过读写端进行操作。
3.匿名管道只支持具有亲缘关系的进程间进行通信。一般是父子进程。本质原因:具有亲缘关系的进程复制了父进程的PCB。
4,当管道为空时,在默认情况下,read会阻塞。
验证:
1 #include<iostream>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<string.h>
5 #include<stdlib.h>
6 using namespace std;
7 int main()
8 {
9 int fk[2]={0};
10 pipe(fk);
11 pid_t pd=fork();
12 if(pd<0)
13 {
14 cerr<<("fork error");
15 exit(1);
16 }
17
18 if(pd>0)
19 {
20 close(fk[0]);
21 sleep(20);
22 const char*str="hello my son ,i am your father";
23 write(fk[1],str,strlen(str));
24 close(fk[1]);
25 cout<<"i send you "<<endl;
26 }
27 else if(pd==0)
28 {
29 close(fk[1]);
30 char buf[128];
31 read(fk[0],buf,128-1);
32 cout<<"i receive your message"<<endl;
33
34 close(fk[0]);
35
36 cout<<buf<<endl;
37 }
38 return 0;
39 }
5,管道的大小为64k。
6,write函数在往文件中写入内容时,若写满,则会阻塞管道。
1 #include<iostream>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<string.h>
5 #include<stdlib.h>
6 #include<stdio.h>
7 using namespace std;
8 int main()
9 {
10 int fk[2]={0};
11 pipe(fk);
12 pid_t pd=fork();
13 if(pd<0)
14 {
15 cerr<<("fork error");
16 exit(1);
17 }
18
19 if(pd>0)
20 {
21 // close(fk[0]);
22 sleep(20);
23 // const char*str="hello my son ,i am your father";
24 int count=0;
25 while(1)
26 {
27
28 // write(fk[1],'i',1);
29 write(fk[1],"c",1);
30 count++;
31 cout<<"after write:"<<count<<endl;
32 }
33 close(fk[1]);
34 cout<<"i send you "<<endl;
35
36 return 0;
37 }
7,匿名管道的生命周期是追随进程的。
8,管道提供字节流服务,字节流:描述符的前后两个数据间没有明显的边界。
9,从管道中读取内容时,不是管道内容的一份拷贝,而是直接将内容拿走。
1 #include<iostream>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<string.h>
5 #include<stdlib.h>
6 #include<stdio.h>
7 using namespace std;
8 int main()
9 {
10 int fk[2]={0};
11 pipe(fk);
12 pid_t pd=fork();
13 if(pd<0)
14 {
15 cerr<<("fork error");
16 exit(1);
17 }
18
19 if(pd>0)
20 {
21 close(fk[0]);
22 const char*str="hello my son ,i am your father";
23 write(fk[1],str,strlen(str));
24 close(fk[1]);
25 cout<<"i send you "<<endl;
26 }
27 else if( pd==0 )
28 {
29 close(fk[1]);
30 char buf[64]={0};
31 while(1)
32 {
33 size_t ret=read(fk[0],buf,64);
34 sleep(5);
35 cout<<ret<<endl;
36
37 }
38 }
39 return 0;
40 }
10,当对管道进行读写操作时,此时若读写的字节数小于pipe_size 512字节,则保证操作的原子性。原子性:执行了,必须要执行完。
11.如果写端不关闭文件描述符,且不写入,则读端可能长时间阻塞。
可能:比如管道内本身就写入了一些内容的话,此时就会读完阻塞。。
12.如果写端在写入完成时,关闭文件描述符,读端在读取完成后,会读到文件尾。
1 #include<iostream>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<string.h>
5 #include<stdlib.h>
6 #include<stdio.h>
7 using namespace std;
8 int main()
9 {
10 int fk[2]={0};
11 pipe(fk);
12 pid_t pd=fork();
13 if(pd<0)
14 {
15 cerr<<("fork error");
16 exit(1);
17 }
18
19 if(pd==0)
20 {
21 close(fk[0]);
22 const char*str="hello my father ,i am your son\\n";
23 int count=0;
24 while(1)
25 {
26
27 write(fk[1],str,strlen(str));
28 cout<<"CHILD :"<<count++<<endl;
29 if(count==3)
30 {
31 close(fk[1]);
32 break;
33 }
34 }
35
36 exit(2);
37 }
38 else if( pd>0 )
39 {
40 int count=0;
41 close(fk[1]);
42 char buf[64]={0};
43 while(1)
44 {
45
46 size_t ret=read(fk[0],buf,64);
47 if(ret>0)
48 {
49 cout<<buf<<endl;
50 sleep(1);
51 }
52 cout<<ret<<endl;
53 sleep(5);
54 }
55
56 // char buf[64]={0};
57 // while(1)
58 // {
59
60 // }
61 }
62 return 0;
63 }
13,如果读端关闭,写端进程可能会被进程直接干掉。
1 #include<iostream>
2 #include<unistd.h>
3 #include<fcntl.h>
4 #include<string.h>
5 #include<stdlib.h>
6 #include<stdio.h>
7 using namespace std;
8 int main()
9 {
10 int fk[2]={0};
11 pipe(fk);
12 pid_t pd=fork();
13 if(pd<0)
14 {
15 cerr<<("fork error");
16 exit(1);
17 }
18
19 if(pd==0)
20 {
21 close(fk[0]);
22 const char*str="hello my father ,i am your son\\n";
23 int count=0;
24 while(1)
25 {
26
27 write(fk[1],str,strlen(str));
28 cout<<"CHILD :"<<count++<<endl;
29 }
30
31 exit(2);
32 }
33 else if( pd>0 )
34 {
35 int count=0;
36 close(fk[1]);
37 char buf[64]={0};
38 while(1)
39 {
39 {
40
41 size_t ret=read(fk[0],buf,64);
42 if(ret>0)
43 {
44 cout<<buf<<endl;
45 sleep(1);
46 }
47 if(count++==3)
48 {
49 close(fk[0]);
50 }
51 }
52
53 // char buf[64]={0};
54 // while(1)
55 // {
56
57 // }
58 }
59 return 0;
60 }
sheel脚本: while : ; do ps axj | grep mypipe | grep -v grep;echo “#########”;sleep 1; done
可以得出子进程已经被干掉–即写端被干掉
获取退出原因:
1 #include<iostream>
2 #include<sys/wait.h>
3 #include<unistd.h>
4 #include<fcntl.h>
5 #include<string.h>
6 #include<stdlib.h>
7 #include<stdio.h>
8 using namespace std;
9 int main()
10 {
11 int fk[2]={0};
12 pipe(fk);
13 pid_t pd=fork();
14 if(pd<0)
15 {
16 cerr<<("fork error");
17 exit(1);
18
19 }
20
21 if(pd==0)
22 {
23 close(fk[0]);
24 const char*str="hello my father ,i am your son\\n";
25 int count=0;
26 while(1)
27 {
28
29 write(fk[1],str,strlen(str));
30 cout<<"CHILD :"<<count++<<endl;
31
32 }
33
34 exit(2);
35
36 }
37 else if( pd>0 )
38 {
39 int count=0;
40 close(fk[1]);
41 char buf[64]={0};
42 while(1)
43 {
44 {
45
46 size_t ret=read(fk[0],buf,64);
47 if(ret>0)
48 {
49 cout<<buf<<endl;
50 buf[ret]='\\0';
51 sleep(1);
52
53 }
54 if(count++==3)
55 {
56 close(fk[0]);
57 break;
58 }
59 }
60
61 }
62
63 int status=0;
64 waitpid(pd,&status,0);
65 cout<<"退出码为"<<(status&0x7F)<<endl;
66
67 }
68 return以上是关于Linux系统编程--进程间通信 ---管道篇的主要内容,如果未能解决你的问题,请参考以下文章