首页 > 系统相关 >Linux | 进程间通信:管道、消息队列、共享内存与信号量

Linux | 进程间通信:管道、消息队列、共享内存与信号量

时间:2024-09-19 23:19:42浏览次数:14  
标签:信号量 int 间通信 管道 Linux 进程 共享内存

文章目录

《深入理解进程间通信:管道、消息队列、共享内存与信号量》

在操作系统中,进程间通信(Inter-Process Communication,IPC)是一个至关重要的概念,它允许不同的进程之间进行数据传输、资源共享、事件通知以及进程控制等操作。本文将详细介绍进程间通信的几种主要方式:管道、消息队列、共享内存和信号量。

一、进程间通信介绍

(一)进程间通信目的

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

(二)进程间通信发展

  1. 管道:是 Unix 中最古老的进程间通信形式。
  2. System V 进程间通信:包括 System V 消息队列、System V 共享内存、System V 信号量。
  3. POSIX 进程间通信:包括消息队列、共享内存、信号量、互斥量、条件变量、读写锁等。

(三)进程间通信分类

  1. 管道:分为匿名管道和命名管道。
  2. System V IPC:包括消息队列、共享内存、信号量。
  3. POSIX IPC:包括消息队列、共享内存、信号量、互斥量、条件变量、读写锁等。

二、管道

(一)什么是管道

管道是从一个进程连接到另一个进程的一个数据流。在 Unix 系统中,管道的使用和文件一致,迎合了“Linux 一切皆文件思想”。

(二)匿名管道

  1. 功能和原型int pipe(int fd[2]);用于创建一无名管道。其中fd是文件描述符数组,fd[0]表示读端,fd[1]表示写端。成功返回 0,失败返回错误代码。
  2. 实例代码:从键盘读取数据,写入管道,读取管道,写到屏幕。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>

int main( void )
{
    int fds[2];
    char buf[100];
    int len;
    if ( pipe(fds) == -1 )
    {
        perror("make pipe");
        exit(1);
    }
    // read from stdin
    while ( fgets(buf, 100, stdin) ) {
        len = strlen(buf);
        // write into pipe
        if ( write(fds[1], buf, len)!= len ) {
            perror("write to pipe");
            break;
        }
        memset(buf, 0x00, sizeof(buf));
        
        // read from pipe
        if ( (len=read(fds[0], buf, 100)) == -1 ) {
            perror("read from pipe");
            break;
        }
        // write to stdout
        if ( write(1, buf, len)!= len ) {
            perror("write to stdout");
            break;
        }
    }
}
  1. 用 fork 来共享管道原理:通过 fork 函数创建子进程,父子进程可以共享管道的文件描述符,从而实现进程间通信。

(三)管道特点

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

(四)命名管道

  1. 创建命名管道
    • 命令行方法:使用mkfifo filename命令创建。
    • 程序创建:使用int mkfifo(const char *filename,mode_t mode);函数创建。
  2. 匿名管道与命名管道的区别
    • 匿名管道由pipe函数创建并打开;命名管道由mkfifo函数创建,打开用open
    • 一旦创建和打开完成后,它们具有相同的语义。
  3. 命名管道的打开规则
    • 如果当前打开操作是为读而打开 FIFO 时:
      • O_NONBLOCK disable:阻塞直到有相应进程为写而打开该 FIFO。
      • O_NONBLOCK enable:立刻返回成功。
    • 如果当前打开操作是为写而打开 FIFO 时:
      • O_NONBLOCK disable:阻塞直到有相应进程为读而打开该 FIFO。
      • O_NONBLOCK enable:立刻返回失败,错误码为ENXIO

三、共享内存

(一)共享内存简介

共享内存区是最快的 IPC 形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不再涉及到内核,换句话说是进程不再通过执行进入内核的系统调用来传递彼此的数据。

(二)共享内存数据结构

struct shmid_ds {
    struct ipc_perm shm_perm; /* operation perms */
    int shm_segsz; /* size of segment (bytes) */
    __kernel_time_t shm_atime; /* last attach time */
    __kernel_time_t shm_dtime; /* last detach time */
    __kernel_time_t shm_ctime; /* last change time */
    __kernel_ipc_pid_t shm_cpid; /* pid of creator */
    __kernel_ipc_pid_t shm_lpid; /* pid of last operator */
    unsigned short shm_nattch; /* no. of current attaches */
    unsigned short shm_unused; /* compatibility */
    void *shm_unused2; /* ditto - used by DIPC */
    void *shm_unused3; /* unused */
};

(三)共享内存函数

  1. shmget 函数
    • 功能:用来创建共享内存。
    • 原型:int shmget(key_t key, size_t size, int shmflg);
    • 参数:
      • key:这个共享内存段名字。
      • size:共享内存大小。
      • shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的。
    • 返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回 -1。
  2. shmat 函数
    • 功能:将共享内存段连接到进程地址空间。
    • 原型:void *shmat(int shmid, const void *shmaddr, int shmflg);
    • 参数:
      • shmid:共享内存标识。
      • shmaddr:指定连接的地址。
      • shmflg:它的两个可能取值是SHM_RNDSHM_RDONLY
    • 返回值:成功返回一个指针,指向共享内存第一个节;失败返回 -1。
      • shmaddrNULL,核心自动选择一个地址。
      • shmaddr不为NULLshmflgSHM_RND标记,则以shmaddr为连接地址。
      • shmaddr不为NULLshmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。公式:shmaddr - (shmaddr % SHMLBA)
      • shmflg = SHM_RDONLY,表示连接操作用来只读共享内存。
  3. shmdt 函数
    • 功能:将共享内存段与当前进程脱离。
    • 原型:int shmdt(const void *shmaddr);
    • 参数:shmaddr:由shmat所返回的指针。
    • 返回值:成功返回 0;失败返回 -1。
    • 注意:将共享内存段与当前进程脱离不等于删除共享内存段。
  4. shmctl 函数
    • 功能:用于控制共享内存。
    • 原型:int shmctl(int shmid, int cmd, struct shmid_ds *buf);
    • 参数:
      • shmid:由shmget返回的共享内存标识码。
      • cmd:将要采取的动作(有三个可取值)。
      • buf:指向一个保存着共享内存的模式状态和访问权限的数据结构。
    • 返回值:成功返回 0;失败返回 -1。

四、消息队列

消息队列提供了一个从一个进程向另外一个进程发送一块数据的方法。每个数据块都被认为是有一个类型,接收者进程接收的数据块可以有不同的类型值。

特性方面,IPC 资源必须删除,否则不会自动清除,除非重启,所以 System V IPC 资源的生命周期随内核。

五、信号量

信号量主要用于同步和互斥。

(一)进程互斥

由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种关系为进程的互斥。系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。在进程中涉及到互斥资源的程序段叫临界区。

特性方面,IPC 资源必须删除,否则不会自动清除,除非重启,所以 System V IPC 资源的生命周期随内核。

进程间通信是操作系统中的重要概念,不同的通信方式各有特点,在实际应用中需要根据具体需求选择合适的方式来实现进程之间的高效通信和协作。

标签:信号量,int,间通信,管道,Linux,进程,共享内存
From: https://blog.csdn.net/TTKunn/article/details/142320412

相关文章

  • ⭐️Linux系统性能调优技巧
    Linux系统性能调优技巧Linux系统性能调优技巧引言1.监控系统性能1.1`top`命令1.2`htop`命令1.3`vmstat`命令1.4`iostat`命令1.5`sar`命令2.优化磁盘性能2.1磁盘分区2.2磁盘阵列2.3固态硬盘(SSD)2.4磁盘调度算法3.优化内存性能3.1内存管理3.2内存分配......
  • Linux驱动开发之ioctl控制定时器并实现任意整数级秒计时器
    在IO模型中,I和O分别代表系统的输入和输出,在计算机中可以直观地理解为输入设备和输出设备,例如鼠标、键盘、显示器等。由于Linux中运行于用户空间的应用程序不能直接对硬件进行操作,需要应用程序向操作系统内核发起调用,将进程切换到内核空间,才能进行IO操作。IO模型根据功能不同......
  • 《现代操作系统》第10章——实例研究1:UNIX、Linux和Android
    《现代操作系统》第10章——实例研究1:UNIX、Linux和Android10.1UNIX与Linux的历史第一次使UNIX的两种流派一致的严肃尝试来源于IEEE(它是一个得到高度尊重的中立组织)标准委员会的赞助。有上百名来自业界、学界以及政府的人员参加了此项工作。他们共同决定将这个项目......
  • linux使用yum命令报错Cannot find a valid baseurl for repo: base/7/x86_64
    【问题】在VMware上安装搭建centOS7虚拟机,配置好网络后,尝试通过yum命令进行安装docker容器。执行命令报错:已加载插件:fastestmirror,langpacksLoadingmirrorspeedsfromcachedhostfileCouldnotretrievemirrorlisthttp://mirrorlist.centos.org/?release=7&arch=x86_......
  • 从方法、操作流程等方面对Windows和Linux的命令进行对比
    Windows和Linux是两个常见的操作系统,它们都有自己的命令行接口。尽管两者的目的都是相同的——执行特定的任务,但它们的命令之间存在一些差异。下面将从方法、操作流程等方面对Windows和Linux的命令进行对比。一、文件和目录操作:列出目录中的文件:–Windows命令:dir–Linux命......
  • Linux系统下安装MegaCli64工具查看和管理raid卡
    命令使用:#/opt/MegaRAID/MegaCli/MegaCli64-LDInfo-Lall-aALL查raid级别#/opt/MegaRAID/MegaCli/MegaCli64-AdpAllInfo-aALL查raid卡信息#/opt/MegaRAID/MegaCli/MegaCli64-PDList-aALL查看硬盘信息#/opt/MegaRAID/MegaCli/MegaCli64-AdpBbuCmd-aAll查看电池信息......
  • Linux命令查看服务器的硬件信息
    Linux命令查看服务器的硬件信息###1、查看服务器产品名称[root@localhost~]#dmidecode|grep"SystemInformation"-A9|egrep"Manufacturer|Product|Serial"Manufacturer:Huawei#厂商ProductName:TaiShan200(Model2280)#......
  • linux监控命令
    分享一部分我写的监控命令,如下:1.cpu监控top-b-n1|grepCpu|awk'{print$2}'|cut-f1-d'%'这个命令返回的是cpu的用户那部分的使用率,就是us那一项,一般情况下我们监控这个指标就可以这个使用率一般超90%需要警告2.磁盘空间监控df-h|awk'{print$NF,$5}'|sed......
  • 如何快速创建一台Linux云服务器?
    轻量应用服务器(TencentCloudLighthouse)是新一代开箱即用、面向轻量应用场景的云服务器产品,助力中小企业和开发者便捷高效的在云端构建网站、小程序/小游戏、电商、云盘/图床以及各类开发测试和学习环境,相比普通云服务器更加简单易用,提供高带宽流量包并以套餐形式整体售卖基础云资......
  • Linux查看日志各种方式
    我发现有很多小伙伴都不会正确地查看日志,总喜欢拿tail和cat去查询,这里我分享一些查看日志的命令。先说结论,less是最适合的一、less方式命令格式1.命令格式:less[参数]文件2.命令功能:less与more类似,但使用less可以随意浏览文件,而more仅能向前移动,却不能向后移动,而且l......