进程间通信(Inter Process Communication,IPC)指代进程间的信息交换,IPC有很多种实现方式,比如:管道通信、信号通信、消息队列、共享内存、信号重组、POSIX信号量等。进程间通信可以实现信息共享、资源共享以及进程控制等功能。
1.管道通信
管道通信是Linux系统提供的一种通信方式,管道通信类似于水管,管道可以被分为读端和写端。在打开管道后,写端和读端都会被分配一个fd,同一个管道可以被同时读或者写,但是读端只可以读取,并且写端只可以写入。
管道提供了一个内核缓冲区,在工作时,A进程调用write()函数写入到管道的内核缓冲区,写入完成后,A进程可以去执行其他工作,但是特别注意,如果缓冲区写满了,write函数会一直阻塞,必须等待B进程read之后才可以继续写入。如想避免阻塞,可以使用fcntl设置O_NONBLOCK将管道设置为非阻塞状态,或者使用poll/select监听管道。
同样的,如果缓冲区为空的,在调用read函数读取时也会产生阻塞,只有当写端所有的fd关闭且缓冲区全空后,read函数才会读取到EOF不会被阻塞。在管道的所有读端的fd关闭之后,如果写端继续写入,程序会收到SIGPIPE信号则会直接导致进程意外终止。
一个管道对象可以拥有多个fd,但是只能拥有一个读端和一个写端。同一个管道的同一个fd不能既读又写,但是一个管道可以被一边读一边写。管道通信最好是用哪端留哪端,不用立即关闭。
同一个fd可以被多个进程同时持有并写入。从应用层的角度看这些写入是同时的,但在内核里,同一时刻只有一个写者能进入临界区,写入操作是被串行化的。通过这种串行写入,可以保证数据的完整性。特别注意,内核仅保证每次的写入是原子的,这个保证大小是有限制的,当数据大于PIPE_BUF的大小(4kb)后,数据将会被拆分为一段一段的写入,此时通常无法继续保证写入数据不出现交错。
匿名管道:
管道在Linux系统中以文件的形式存在,Linux系统中的管道文件分为匿名管道(pipe)和命名管道(fifo),匿名管道的特点是没有名称,故用户无法调用open进行打开,在Linux系统中提供了系统调用接口pipe用于创建匿名管道并且返回fd。
pipe接口的标准pipe (int __pipedes[2]),传入为一个包含两个数据的整形数组,假设使用pipe(fd)调用后,fd[0]将为读端fd,fd[1]为写端fd。
由于匿名管道的特性,其fd仅可以通过父进程创建后分发给子进程间进行通信,即其必须来源于同一个父进程。下面是一个匿名管道的使用例程。
#include <stdio.h>
#include <string.h>
#include <sys/wait.h>
#include <unistd.h>
int main(){
char str[20] = {};
int fd[2];
if(pipe(fd)){
printf("创建管道失败!\n");
return 0;
};
pid_t pid = fork();
if(pid == -1){
printf("子进程创建失败!\n");
return 0;
}
if (pid == 0) {
fflush(stdout);
while (1) {
read(fd[0], str, 20);
printf("\n[子进程]:收到来自父进程的消息:%s\n", str);
if (!strcmp(str, "结束通信")) {
break;
}
}
_exit(NULL);
}else {
while (1) {
printf("[父进程]请输入要传递给子进程的消息:");
fflush(stdout);
scanf("%s", str);
write(fd[1], str, strlen(str)+1);
if (!strcmp(str, "结束通信")) {
break;
}
}
printf("结束!\n");
wait(NULL);
}
return 0;
}
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://zixblog.com/zix/uncategorized/linuxxitongjinchengjiantongxin/