《Linux从0到99》十 进程间通信

Posted AURORA_CODE

tags:

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

一、 什么是进程间通信

1. 进程间通信的目的

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

2. 进程间通信的分类

管道

  • 匿名管道
  • 命名管道

System V IPC

  • system V 消息队列
  • system V 共享内存
  • system V 信号量

POSIX IPC

  • 消息队列
  • 共享内存
  • 信号量
  • 互斥量
  • 条件变量
  • 读写锁

二、 管道

  • 管道是Unix中最古老的进程间通信的形式。
  • 从一个进程连接到另一个进程的一个数据流称为一个“管道"

1. 管道

01 管道的符号

ps aux | grep xxx

  • ps 本质上都是可执行程序
  • grep 可执行程序

02 管道的本质

管道在内核当中是一块缓冲区,供不同的进程读写的缓冲区

2. 匿名管道与命名管道

01 匿名管道

int pipe(int pipfd[2]);

  • pipefd:数组,输出型参数。
  • pipefd[0],pipefd[1]是pipefd函数填充的,参数当中保存的值是文件描述符,俩个文件描述符分贝对应管道读写俩端。
  • pipefd[[0]:管道的读端。
  • pipefd[1]:管道的写端。
  • 返回值: 0: 匿名管道创建成功。 -1:匿名管道创建失败。



特性:

  • 管道是半双工通信的,数据流只能从写端流向读端
  • 匿名管道在内核创建出来的缓冲区是没有标识符的,导致了其他进程没有办法之间找到这个缓冲区。但是创建的进程可以通过读写俩端的文件描述符进行操作。
  • 匿名管道值支持具有亲缘惯性系的进程进行进程间通信
  • 当文件描述符保持基础属性(阻塞),调用read读空管道的时候,则read函数就会阻塞;
  • 管道的大小为64k;
  • 当文件描述符保持基础属性(阻塞),一直调用write将管道写满之后,则wirte函数就会阻塞。
  • 管道的生命周期是跟随进程的
  • 管道提供字节流服务
  • 从fd[1]当中读取内容的时候,是直接将数据读走了,并不是拷贝
  • 管道的大小:64K
  • 当对管道进行读写的时候,如果读写的字节大小没超过pipe_size,则管道保证读写的原子性。

代码验证:

#include <stdio.h>
#include <string.h>
#include <unistd.h>
int main()
{
    int fd[2];
    int ret = pipe(fd);
    if(ret == -1)
    {
        perror("pipe:");
        return 0;
    }
    printf("fd[0] : %d\\nfd[1] : %d\\n",fd[0],fd[1]);
    pid_t pid = fork();
    if(pid < 0)
    {
        perror("fork:");
        return 0;
    }
    else if(pid == 0)
    {
        // 子进程
        close(fd[1]);
        char buff[1024]={0};
        read(fd[0],buff,sizeof(buff)-1);
        printf("child read : %s\\n",buff);
    }
    else 
    {
        // 父进程
        close(fd[0]);
        char buf[1024]="I am father!";
        write(fd[1],buf,strlen(buf));
    }
    while(1)
    {
        sleep(1);
    }
    return 0;
}

02 命名管道

区别于匿名管道,是由标识符标识的管道,其他进程可以通过管道标识栈找到该管道。
①创建命名管道
命令创建: mkfifo
函数创建: mkfifo函数
int mkfifo(const char *pathname, mode_t mode);
pathname : 要创建的命名管道文件的路径
mode_t : 命名管道的文件权限,八进制数字(0664)
②特性
支持不同进程进行进程间通信的

代码实现:

//read.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    int fd = open("./fifo",O_RDONLY);
    if(fd < 0)
    {
        perror("open");
        return 0;
    }
    char buf[1024]={0};
    read(fd,buf,1024);
    printf("%s",buf);
    return 0;
}

//write.c
#include <stdio.h>
#include <unistd.h>
#include <fcntl.h>

int main()
{
    int fd = open("./fifo",O_WRONLY);
    if(fd < 0)
    {
        perror("OPEN:");
        return 0;
    }
    char buf[]="I am process A!";
    write(fd,buf,sizeof(buf)-1);
    return 0;
}

三、 消息队列

  • 消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法
  • 每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值特性方面
    • IPC资源必须删除,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核

四、 共享内存

1. 共享内存的原理

  • 在物理内存当中开辟一段空间
  • 不同的进程通过页表将该空间映射到自己的进程虚拟地址空间当中
  • 不同的进程通过操作自己进程虚拟地址空间当中的虚拟地址,来操作共享内存。

2. 共享内存接口

01 shmget

int shmget(key_t key,size_t size,int shmflg);

  • key : 共享内存标识符
  • size : 共享内存大小
  • shmflg : 共享内存的属性信息
    IPC_CREAT : 共享内存不存在的话,则创建共享内存
    IPC_EXCL | IPC_CREAT:如果共享内存存在,则报错。如果共享内存不存在,则创建。引申含义 : 一定要获取一个是自己创建的共享内存。
    按位或上共享内存的权限,权限也是八进制数字
  • 返回值:成功则返回共享内存的操作局柄

02 shmat

void *shmat(int shmid, const void *shmaddr, int shmflg);

  • shmid : 共享内存操作句柄
  • shmaddr :将共享内存附加到共享区当中的那一个地址,一般是传递NULL的值,让操作系统进行分配。
  • shmflg : SHM_RDONLY : 只读方式。
  • 返回值: 成功: 返回附加的虚拟地址, 失败返回NULL

03 shmdt

int shmdt(const void *shmaddr);

  • shmaddr : shmat的返回值

04shmctl

int shmctl(int shmid,int cmd,struct shmid_ds *buf);

  • shmid :共享内存操作局柄
  • cmd : 告诉shmctl函数完成什么事情

IPC_SET :设置共享内存属性信息, 通过第三个参数获取(入参)
IPC_STAT :获取共享内存属性信息,通过第三个参数获取(出参)
IPC_RMID : 删除共享内存, 第三个参数传递NULL

  • buf :共享内存数据结构buf

3. 共享内存的特性


以上就是这篇文章的所有内容啦,感谢老铁有耐心看完。有啥错误请多多指正哈!码字不易,希望大佬们点个赞

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

《Linux从0到99》十 进程间通信

Linux Linux程序练习十五(进程间的通信共享内存版)

Linux从青铜到王者第九篇:Linux进程间通信第一篇

linux进程间通信之System V共享内存详解及代码示例

嵌入式Linux从入门到精通之第十一节:进程间通信

《Linux从0到99》八 进程控制