Linux----进程间通信

Posted 4nc414g0n

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Linux----进程间通信相关的知识,希望对你有一定的参考价值。

进程间通信

1)引入

进程间通信可以:

  1. 数据传输:一个进程需要将它的数据发送给另一个进程
  2. 资源共享:多个进程之间共享同样的资源
  3. 通知事件:一个进程需要向另一个或一组进程发送消息,通知它(它们)发生了某种事件(如进程终止时要通知父进程)
  4. 进程控制:有些进程希望完全控制另一个进程的执行(如Debug进程),此时控制进程希望能够拦截另一个进程的所有陷入和异常,并能够及时知道它的状态改变

2)管道

Ⅰ匿名管道pipe

我们用到的 ‘|’ 其实就是匿名管道

#include <unistd.h>
int pipe(int pipefd[2]);
#define _GNU_SOURCE /* See feature_test_macros(7) */
#include <fcntl.h> /* Obtain O_* constant definitions */
#include <unistd.h>
int pipe2(int pipefd[2], int flags);
功能:创建一个管道,一个可用于进程间通信的单向数据通道
解释:

  1. pipefd[2]: 输出型参数,拿到两个文件描述符数组 pipefd 用于返回引用的两个文件描述符,pipefd[0] 指的是管道的读取端。 pipefd[1] 指的是管道的写端
  2. flags:如果 flags 为 0,则 pipe2() 与 pipe() 相同。 可以在标志中对以下值进行按位或运算以获得不同的行为

返回值:

  1. 返回值:成功返回0,失败返回错误代码

下面是一个例子,子进程向父进程传送数据(文件描述符表示)
:为什么要打开(读、写)两个文件?
:1. 只以读/写打开,子进程也只能继承读/写,不能使用管道 2. 为了灵活通信
:为什么父子进程要关闭?
:语义上证明管道的单向特性,防止误操作

①匿名管道特性(MARK一下)

特性:

  1. 管道自带同步机制
  2. 管道是单向通信的
  3. 管道是面向字节流(写入数据的量和读出数据的量互不相关)的
  4. 管道只能保证是具有血缘关系的进程进程通信常用于父子
  5. 管道可以保证一定程度的数据读取的原子性写入

注意: 进程退出,曾经打开的文件也会被关掉。管道也是文件,管道的生命周期跟随进程

②验证匿名管道的特性:同步

测试代码:

int main()

	int pipefd[2]=0;
	if(pipe(pipefd)<0)//创建管道
	
       perror("pipe");
       return 1;
	
	pid_t id = fork();
	if(id < 0)
       perror("fork");
       return 1;
	
	else if(id == 0) //child
       close(pipefd[0]);
       int count=5;
       const char* msg="The mesage send to parent\\n";
       while(count)
               write(pipefd[1],msg,strlen(msg));
               sleep(1);
               count--;
       
       close(pipefd[1]);
       exit(0);
	
	else//parent
       close(pipefd[1]);
       char buffer[64];
       while(1)
	        buffer[0]=0;//清空buffer
	        ssize_t size=read(pipefd[0],buffer,sizeof(buffer)-1);//最后一个\\0去了
	        if(size>0)
               buffer[size]=0;//添加\\0
               printf("recieve from child: %s",buffer);
	        
	        else if(size == 0)
               printf("pipe close,child quit\\n");
               break;
	        
	        else
	            break;//TODO
       
       int status=0;
       if(waitpid(id,&status,0)>0)
       	printf("wait success\\n");
	
	return 0;


父进程没有设置sleep(1)却每隔1秒才打印
从结果我们可以得出在子进程没有写入的时候,父进程处于等待状态


当我们把写端改为一直写,读端不读,当达到最大写入时会停下来等有空间再进行写入

while(1)
	write(pipefd[1],msg,strlen(msg));
	//sleep(1);
	printf("write:%d",count);
	count++;

//father:sleep(100);


可以得出在读端没有读的时候,写端处于等待状态


关闭父进程的读端,同时打印一下退出码(status&0x7f)

else//parent
	close(pipefd[1]);
	close(pipefd[0]);


写端被OS发送SIGPIPE信号杀死


关闭子进程的写端

else if(id == 0) //child
	close(pipefd[0]);
	close(pipefd[1]);


父进程的read接收到0,文件结束

总结

写端读端结果
不读写端阻塞
不写读端阻塞
关闭写端被OS发送SIGPIPE信号杀死
关闭父进程的read接收到0,文件结束

③管道大小

使用ulimit -a查看系统资源

验证:
让child每次写入一个字节记录次数

观察到近似65535字节,64KB


两个结果为什么不一样呢?
man 7 pipe可以看到一句话:超过PIPE BUF(4KB)的不具有原子性

4kb的pipe size其实是以原子性写入管道的单元大小


Ⅱ命名管道

①用处

匿名管道应用的一个限制就是只能在具有共同祖先(具有亲缘关系)的进程间通信,如果我们想在不相关的进程之间交换数据,可以使用FIFO文件来做这项工作,它经常被称为命名管道,命名管道是一种特殊类型的文件

②指令mkfifo

指令mkfifo [文件名],创建一个有名管道

指令测试

输入重定向到myfifo

③函数mkfifo

#include <sys/types.h>
#include <sys/stat.h>
int mkfifo(const char *pathname, mode_t mode);
功能:在pathname下创建一个命名管道
解释:

  1. pathname:路径/文件名
  2. mode:(mode & ~umask)是文件的8进制权限,例如0644

返回值:

  1. 成功返回0,失败-1

测试代码:
server.c

int ret=mkfifo("./fifo",0644);
if(ret==-1)
	perror("mkfifo");
	return 1;

int fd=open("./fifo",O_RDONLY);
if(fd<0)
	perror("open");
	return 2;

char buffer[128];
while(1)
 buffer[0]=0;//清空
 ssize_t size=read(fd,buffer,sizeof(buffer)-1);
 if(size>0)
	  buffer[size]=0;
	  printf("client :> %s\\n",buffer);
 
 else if(size==0)
	  printf("client quit\\n");
	  break;
 
 else
	  break;

close(fd);
return 0;

client.c

int fd=open("./fifo",O_WRONLY);
if(fd<0)
   perror("open");
   return 2;

printf("Please Enter:>\\n");
fflush(stdout);
char buffer[128];
while(1)
	buffer[0]=0;//清空
	ssize_t size=read(0,buffer,sizeof(buffer)-1);//fd==0就是stdin键盘输入
	if(size>0)
	    buffer[size]=0;
	    write(fd,buffer,strlen(buffer));
	
	else if(size==0)
	    break;
	
	else
	    break;

close(fd);
return 0;

结果:

3)system V IPC

System V 消息队列

System V 共享内存

System V 信号量

4)POSIX IPC

消息队列

共享内存

信号量

互斥量

条件变量

读写锁

以上是关于Linux----进程间通信的主要内容,如果未能解决你的问题,请参考以下文章

简述Linux进程间通信的几种方式

Linux进程间通信简介

深刻理解Linux进程间通信(IPC)

深刻理解Linux进程间通信(IPC)

Linux进程通信之匿名管道

Linux 进程间通信