TTTTTTZZZZZZ(系统编程---进程间通信)8

为什么要进行进程间通信?

进程之间具有独立性,每个进程都有自己的虚拟地址空间,进程并不知道其他进程的虚拟地址空间中的数据类容
就好比一个人不能知道另一个人脑子里在想啥是一样的

进程间通信需要“介质”,两个进程都能访问到的公共资源

借助文件就可以完成进程间通信,最简单的进程间通信方式

操作系统专门提供的进程间通信方式

1.匿名管道
2.命名管道
3.消息队列
4.共享内存
5.信号量
6.互斥量
7.条件变量
8.读写锁

最重要的进程间通讯方式 网络,网络是一种更牛逼的进程间通信,不仅可以在一台主机上,还可以跨主机

| 就叫匿名管道,所以 | 就是进程间通信,|前是一个进程,|后是另外一个进程

管道只能进行单向通信
在这里插入图片描述

管道就是内核中的一块内存(构成了一个队列),使用一对文件描述符来进行访问这个内存,读文件描述符就是在队列中取数据,写文件描述就是往队列中插入数据
int pipe(int fildes[2]);

int pipe(int fildes[2]);
参数是一个传入传出参数
fildes文件描述符数组,fd[0],表示读端,fd[1]表示写端

//实际应用

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<string.h>
  4 #include<sys/wait.h>
  5 int main()
  6 {
  7   int fd[2];
  8   size_t ret1 = pipe(fd);
  9   if(ret1 < 0)
 10   {
 11     perror("pipe");
 12   }
 13   ret1 = fork();
 14   if(ret1 > 0)
 15   {
 16     char buf[1024] = "八百里开外,一枪就干掉鬼子的机枪手";
 17     write(fd[1],buf,strlen(buf)); //做人留一,日后好相见                                                                            
 18     wait(NULL);
 19   }
 20   else if(ret1 == 0)
 21   {
 22     char buf[1024] = {0};
 23     ssize_t n = read(fd[0],buf,sizeof(buf)- 1);
 24     buf[n] = '\0';//双重保障
 25     printf("%s\n",buf);
 26   }
 27   else
 28   {
 29     perror("fork");
 30   }
 31   //使用完管道之后要记得关闭管道
 32   close(fd[0]);
 33   close(fd[1]);
 34   return 0;
 35 }

画图大概就是这个意思:
在这里插入图片描述

1.创建子进程的时候子进程会继承父进程的文件描述符表,此时子进程也能访问到一个相同的管道(前提是管道是在创
  建子进程之前创建的)父进程写管道的时候,子进程就能从管道中读取出数据反之亦然
2.可以将管道理解成队列,水管,水管中的数据是不断在流动着的,从管道中将数据读到之后就会将数据从管道中删
  除,并不是一直都在,管道中的数据是时刻发生变化的。
  管道是可以一边写一边读的。
3.管道中的数据一旦被读了之后,数据出队列了,不可能两个进程读到相同的数据,
4.假如有多个进程同时去尝试读,只有一个进程能读到数据,其他进程就读不到
5.管道内置了同步互斥机制,在这个机制下,不可能存在两个管道一人读到一半数据的情况

同步互斥机制:
1.多个进程同时去读写管道的时候,数据不会发生错乱
2.如果管道为空尝试读就会在read()函数出阻塞
3.如果管道满了,尝试写就会在write()处阻塞
管道在内核中,既然在内核中显然是有大小的,默认的管道的大小是64kb,因为太小了,所以基本不会用

如果一个进程创建的所有的管道写端对应的文件描述符被关闭,则read返回0
如果一个进程创建的所有的管道的读端对应的文件描述符被关闭,则write也可能因为操作系统给出的信号而退出。

管道的特点:
1.只能用于具有公共祖先的进程(具有亲缘关系的进程)之间进行通信;通常,一个管道由一个进程创建,然后该进程
调用fork()函数,此后父子进程之间就可以进行通信了
2.管道提供流式服务
3.一般而言,进程退出,管道释放,所以管道的生命周期和进程生命周期有关,等到所用引用同一个进程的管道都退出
之后,管道才能释放
4.一般而言,内核会对管道操作进行同步与互斥操作
5.管道是半双工,数据只能向一个方向流动;需要双方通信的时候,需要建立两个管道

============================================================================

命名管道:

命名管道和匿名管道的唯一区别就是,命名管道可以支持任何进程通信,不只是有亲缘关系的

1.使用 mkfifo 命令创建名命管道

LINUX中的七种文件类型

d 目录文件。 
l 符号链接(指向另一个文件,类似于window下的快捷方式); 
s 套接字文件; 
b 块设备文件,二进制文件; 
c 字符设备文件; 
p 命名管道文件; 
- 普通文件。

LINUX中的七种文件类型

//插入vim快捷键
:tabe [filename]以标签页的方式打开文件
gt切换到下一个标签
gT切换到上一个标签页
:q 退出当前打开的标签页
:qa关闭所有的标签页

底行模式输入:set mouse=a就可以使用鼠标点击标签页,但是就不能使用鼠标来进行复制粘贴了
再想使用复制粘贴的话就:set mouse-=a

如果所有写端关闭读端返回0,
利用全双工通信管道实现一端读,一端写的程序

//写端
#include<stdio.h>                                                                                                                 
  2 #include<unistd.h>
  3 #include<fcntl.h>
  4 #include<string.h>
  5 int main ()                        
  6 {           
  7   int fd = open("./myfifo",O_RDWR);
  8   if(fd < 0)       
  9   {
 10     perror("open");
 11   }
 12   while(1)               
 13   {                                        
 14     char buf[1024] = {0};
 15     read(0,buf,sizeof(buf)-1);
 16     int n = write(fd,buf,strlen(buf));
 17     printf("[write]:%d\n",n);
 18   }  
 19   return 0;
 20 }    
//读端
#include<stdio.h>                                                                                                                 
  2 #include<unistd.h>
  3 #include<fcntl.h>
  4 int main(){       
  5   int fd = open("./myfifo",O_RDWR);
  6   if(fd < 0)
  7   {                                
  8     perror("open");
  9   }
 10   while(1)         
 11   {
 12     char buf[1024] = {0};
 13     ssize_t n = read(fd,buf,sizeof(buf)-1);
 14     if(n < 0)            
 15     {                         
 16       perror("read");                 
 17       return -1;             
 18     }
 19     else   
 20     {
 21       buf[n] = '\0';
 22       printf("[read]%s",buf);
 23       fflush(stdout);
 24     }
 25   }
 26   close(fd);
 27   return 0;
      }

命名管道的生命周期也是跟随进程。myfifo这个文件仅仅是一个入口,管道的本体仍然是内核中的一个内存。生命周期实际上是围绕这个内核中的内存来讨论的

============================================================================
共享内存:
共享内区是最快的IPC(进程间通信)形式。

共享内存的使用方式:

1.在内核中先创建处共享内存对象
2.多个进程附加到这个共享内存对象上,使用shmat函数
3.就可以直接读写这个共享内存了

//共享内存使用举例
代码不重要,理解过程,两个进程映射到同一块内存(资源)上再进行通信

//myshm.h文件,主要是把一个会重复用到的函数封装起来,方便调用,其次是函数是static类型的,因为使用的是c语言编译,
//假如不适用static的话那么这个.h文件被多个.c文件包含的话就会出现函数的重复定义,在c++中可以使用添加
//inline的方式来定义为内联函数,那么就会直接再调用出进行展开,就不存在相同函数的重复定义,但是在c语言中,
//假如要在.h文件中,把函数的声明和定义写在一起,就要在只能使用static关键字
//下面这段函数是创建共享内存的,固定格式,要修改的话只需要修改固定的参数就可以,没必要深究
  1 #pragma once
  2 #include<sys/shm.h>
  3 #include<stdio.h>
  4 #include<unistd.h>
  5 #include<fcntl.h>
  6 #include<sys/shm.h>
  7 static int CreateShm()
  8 {
  9   key_t key = ftok(".",0x2);
 10   if(key == -1)
 11   {
 12     perror("ftok");
 13     return -1;
 14   }
 15   int ret = shmget(key,1024,IPC_CREAT | 0666);
 16   if(ret < 0)  //判断是否申请成功
 17   {
 18     perror("shmget");
 19     return 1;
 20 
 21   }
 22   return ret;                                                                                                                          }                                                                                                                                
 23 
//用来读共享内存中内容的文件
  1 #include"myshm.h"
  2 int main()
  3 {
  4   //1.创建共享内存,或者打开已经创建好的共享内存
  5   //ret不是别的就是我们已经打开的共享内存的句柄,可以通过句柄去使用共享内存
  6   //查看CreateShm,我们刚开始在创建共享内存的时候就已经把大小指定好了
  7   int ret = CreateShm();
  8   //2.附加到共享内存上
  9   char* p =(char*)shmat(ret,NULL,0);
 10   //将本进程附加到共享内存上,返回的就是共享内存的指针
 11   //直接就可以使用了,这块内存和malloc创建的内存差不多,可以直接使用
 12   printf("[read]%s\n",p);  //打印读到的内容                                                                                                        
 13   return 0;
 14 }
//往共享内存中写的.c文件
  1 #include"myshm.h"
  2 #include<string.h>
  3 int main()
  4 {
  5   int  ret = CreateShm();
  6   char* p = (char*) shmat(ret,NULL,0);
  7   //写入内容
  8   strcpy(p,"蛤蟆买皮皮");                                                                                                           
  9 
 10   return 0;
 11 }

在这里插入图片描述
共享内存比管道还要底层,写入共享内存的数据不会因为你读出就消失,在共享内存释放的时候数据就消失了

共享内存起码还是封装过的,实现了互斥什么的功能?

ipcs -m 查看系统中的共享内存
共享内存的生命周期随内核,共享内存一直会存在到手动释放,或者内核重启,也就是重新开机关机,就改变了

IPC本质:进程间通信就是因为进程与进程之间相互独立,需要借助公共资源进行通信
如果一个程序已经运行起来的,还在运行中,此时你就可以通过gdb attach的方式来调试代码

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值