关于C语言中进程通信的5种方式

进程通信

操作系统中每个进程地址空间相互独立,进程间通信必须经过内核

广义进程通信方式

  1. 文件
  2. 管道
  3. 内存映射
  4. 共享内存
  5. 信号
  6. 套接字
  7. 消息队列
  8. 剪切板
  9. 远程过程调用

单机环境中常见的进程通信方式

管道通信

管道通信也成为匿名管道。管道通信使用方式最简单,用于有血缘关系的进程间通信。

主要特点

  • 使用两个文件描述符,一端表示读,一端表示写
  • 两个进程都终结管道才终结
  • 读端以及写端默认是阻塞
  • 本质是一个内核缓冲区,使用循环队列实现,
  • 不可反复读取

函数原型

/**
 * 参数:
 *   数组中[0]、[1]分别代表读端和写端
 * 返回值:
 *   成功返回0
 *   失败返回-1,并设置errno值
 */
int	 pipe(int [2])

命名管道

区别于管道通信,命名管道(FIFO)可以进行没有关联的进程间通信。

主要特点

  • FIFO是Unix/Linux基础文件类型的一种,文件类型用p标识
  • FIFO在文件磁盘上数据快大小为0,仅用来标识内核中的通道

使用方式

  1. 创建管道文件

    管道文件严格遵循先进先出的方式,读取从开始处返回数据,写入将数据添加到末尾

  • 使用命令创建管道文件
    mkfifo 管道名
    
  • 函数创建
    /**
     *参数:
     *  1:文件名
     *  2:权限
     * 返回值:
     *   文件描述符
     */
    int mkfifo(const char *, mode_t);
    
  1. 操作文件
    管道文件与普通文件使用方式相同,系统的文件操作函数都可用于管道文件。

内存映射

存储映射是使磁盘中的文件与内存中的缓冲区相映射。
在缓冲区中读取数据,相当于读取文件中的数据;将数据写入缓冲区,相当于写入文件。
这样就可以只使用指针来完成I/O操作,可以用于无关联的进程之间的通信。

使用方式

  1. 打开文件

  2. 函数调用

    /**
     * 参数:
     *   1:映射起始地址,一般设置NULL,由操作系统指定
     *   2:映射长度
     *   3:读写模式
     *   4:写入映射区是否写入到文件中(MAP_ANONYMOUS匿名映射)
     *   5:步骤1中打开的文件描述符(当文件描述符为-1使用匿名映射)
     *   6:文件偏移长度
     * 返回:
     *   映射区首地址(内存块,与数组相似)
     */
    void *  mmap(void *, size_t, int, int, int, off_t)
    
  3. 释放资源

    /**
     * 参数:
     *   1:地址
     *   2:映射长度
     *  返回值:
     *  成功返回0
     *  失败返回-1
     */ 
    int munmap(void *, size_t) 
    

信号

信号是信息的载体。当一个进程收到信号后,暂停运行,去执行信号处理函数,类似于中断。

信号的三种状态

  • 产生
    信号的产生包含按键、系统调用、软件条件、异常以及命令等方式。

  • 未决
    产生和递达之间的状态,主要由于阻塞或者屏蔽产生。

  • 递达
    送达到进程中。

使用方式

  1. 信号处理函数
    /**
     * 信号处理函数
     * 函数名自定义
     */ 
    void handle(int)
    
  2. 注册信号处理函数
    方式一
    /**
     * signal函数参数:
     *   1:信号编号
     *   2:信号处理函数
     */
    void(*signal(int, void (*)(int)))(int);
    
    方式二
    /**
     * sigaction函数参数:
     *   1:信号编号
     *   2:传入参数:新的信号处理方式
     *   3:传出参数:旧的信号处理方式
     * 返回值:
     *   是否成功
     */
    int	sigaction(int, const struct sigaction * __restrict,
    	    struct sigaction * __restrict);
    

❗❗合理使用信号阻塞能够解决进程间的同步问题。

共享内存

共享内存的实质是将内核的一块内存映射到进程中,操作本地的内存相当与操作共享内存,用于无关联的进程之间。

使用方式

  1. 创建共享内存

    /**
     * 函数参数:
     *   1:共享内存唯一key
     *   2:共享内存大小
     *   3:创建模式以及权限
     * 返回值:
     *   成功:返回共享内存ID(与key不一定相同)
     *   失败:返回-1
     */
    int shmget(key_t, size_t, int);
    
  2. 关联共享内存

    /**
     * 函数参数:
     *   1:共享内存ID
     *   2:设置当前进程中的内存地址(与共享内存地址不一定相同),一般为NULL
     *   3:读写模式
     * 返回值:
     *   成功:当前内存地址
     *   失败:返回-1(void *)
     */
    void *shmat(int, const void *, int);
    
  3. 读写内存

    与数组操作基本一致,操作共享内存地址。

  4. 断开共享内存

    /**
     * 函数参数:
     *   当前进程相关联的内存地址
     * 返回值:
     *   成功与否
     */
    int shmdt(const void *);
    
  5. 删除共享内存

    /**
     * 函数参数:
     *   1:共享内存ID
     *   2:操作(获取状态信息、设置信息、删除)
     *   3:内容
     * 返回值:
     *   成功与否
     */
    int shmctl(int, int, struct shmid_ds *)
    

😄 此文档只作抛砖引玉,详细原理仍需要深入研究。

  • 3
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值