【linux】进程间通信(二)

6. 命名管道

命名管道可以实现两个毫不相干的进程之间的通信

(一)创建一个命名管道

  • 命令行上创建

mkfifo + 管道名

  • 函数调用

int mkfifo(const char *filename,mode_t mode)

filename:

文件名

mode:

权限
代码

(二)匿名管道与命名管道的区别

  1. 匿名管道由pipe函数创建并打开 ;命名管道由mkfifo函数创建,打开用open
  2. FIFO(命名管道)与pipe(匿名管道)之间唯一的区别在它们创建与打开的方式不同,一但这些工作完成之后,它们具有相同的语义

(三)命名管道的打开规则

命名管道创建后,必须需要既有 进程以读方式打开命名管道,又有进程以写方式打开命名管道(例如,如果只有读方式打开了,open会阻塞,只有别的进程以写方式打开,读的进程才会继续向后执行代码)

7. system V共享内存

共享内存区是最快的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 */

};

(二)共享内存函数

shmget函数

功能:用来创建共享内存

原型

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

参数

key:这个共享内存段名字 (保证进程看到的是同一份共享内存,且在操作系统内标定唯一性)

size:创建的共享内存大小 (单位字节)

shmflg:由九个权限标志构成,它们的用法和创建文件时使用的mode模式标志是一样的 (标定如何创建共享内存)

返回值 shmid:成功返回一个非负整数,即该共享内存段的标识码(进程内,标定资源的唯一性);失败返回-1

注意:

共享内存的大小一般建议设置成4096(4KB)的整数倍

  • 更详细讲 参数shmflg
  1. IPC_CREAT(单独使用):创建一块共享内存,如果没有,就申请;如果有,就获取并返回
  2. IPC_CREAT | IPC_EXCL : 创建一块共享内存,没有就申请,如果已经有了,就出错返回(确保获取到的共享内存一定是新申请的)

注意:

IPC_EXCL不单独使用

  • 更详细讲 参数key
  1. key是一个数字,它在内核中具有唯一性,能让不同的进程进行唯一性标识
  2. 第一个进程可以通过key创建共享内存,第二个进程只要拿着key,就能找到和第一个进程访问一样的共享内存
  3. 对于一个已经创建好的共享内存,key在共享内存描述对象中

ftok函数

功能:得到key

原型

int ftok(const char* pathname,int proj_id);

参数

pathname: 路径

proj_id: 用户自己定义id

返回值:返回 key ;失败返回-1 , 如果失败,则表示已经有对应key的共享内存,把 proj_id换一下即可

注意:

这里有一套算法,将 pathname 和 proj_id 进行数值计算得到 key

shmat函数

功能:将共享内存段连接到进程地址空间

原型

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

参数

shmid: 共享内存标识

shmaddr:指定连接的地址 ,可以设置称NULL

shmflg:它的两个可能取值是SHM_RND和SHM_RDONLY ,也可以直接设置成0

返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1

最简单的方法,设置 shmaddr = NULL , shmflg = 0

  • 更详细讲 参数shmaddr

shmaddr为NULL,核心自动选择一个地址

shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址

shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍 公式:shmaddr - (shmaddr % SHMLBA)

shmflg = SHM_RDONLY,表示连接操作用来只读共享内存

shmdt函数

功能:将共享内存段与当前进程脱离

原型

int shmdt(const void *shmaddr);

参数

shmaddr: 由shmat所返回的指针

返回值:成功返回0;失败返回-1

注意:

将共享内存段与当前进程脱离不等于删除共享内存段

shmctl函数

功能:用于控制共享内存

原型

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

参数

shmid:由shmget返回的共享内存标识码

cmd:将要采取的动作(有三个可取值)

buf:指向一个保存着共享内存的 模式状态和访问权限的数据结构

返回值:成功返回0;失败返回-1

  • ipcs -m

显示已有的共享内存信息

  • ipcrm -m + shmid

删除对应共享内存标识符的共享内存

(三)共享内存的特性

  1. 共享内存没有同步互斥之类的保护机制
  2. 共享内存是所有的进程间通信中最快的
  3. 共享内存的数据,是由用户自己维护的(记得要去关联和释放)

(四)共享内存存在的一些问题

当存在两个进程,进程A正在向共享内存写入数据,写入一部分时,B拿走了,导致双方发送和接受的数据不完整

  1. 两个进程看到同一份资源 ------ 共享资源,如果不加保护,会导致数据不一致的问题
  2. 任何时刻,只允许一个执行流访问一个共享资源时,叫做加锁
  3. 任何时刻,只有一个执行流访问一个共享资源叫临界资源
  4. 访问临界资源的代码叫做临界区

8. system V消息队列

(一)画图了解消息队列

  • ipcs -q

查看已存在的消息队列

  • icprm -q + msqid

删除该消息队列标识符的消息队列

(二)消息队列函数(简写)

msgget函数

功能:创建消息队列

原型:

int msgget(key_t key,int msgflg);

msgctl函数

功能:用于控制消息队列

原型:

int msgctl(int msqid,int cmd,struct msqid_ds *buf);

注意:

IPC在内核中的数据结构设计,在操作系统中,所有的IPC资源都是整合进操作系统的IPC模块中

(所有IPC数据结构都有 ipc_perm 类型的成员变量,这些都被放进 struct ipc_perm* 的数组里面管理起来,数组的下标对应的就是 xxx标识符)

9. system V信号量

(一)理解信号量

信号量/信号灯本质是一把计数器,用来描述临界资源中资源数量的多少

(二)信号量总结点

注意:

  1. 申请信号量资源成功,就代表该进程具有访问资源的权限
  2. 申请了信号量资源,不代表就一定访问了该资源,只是对这个资源的预定机制
  3. 信号量可以有效保证共享资源的执行流的数量
  4. 每一个执行流,想要访问共享资源中的一部分时,不是直接访问,而是先申请信号量资源
  5. 把值为1,0的"计数器"叫做 二元信号量 -------- 本质就是一个锁
  6. 申请信号量,本质是对计数器减减,即P操作;释放信号量,本质是对计数器加加,即V操作
  7. 申请和释放都是原子的(即要么做完,要么不做)
  8. 信号量本质上也是一种共享资源,所以要先保护好自己,才能对别的临界资源进行保护
  9. 信号量也是进程通信的一种:通信不仅仅是通信数据,互相协同也是
相关推荐
阿雄不会写代码2 分钟前
ubuntu安装nginx
linux·服务器·网络
chinayu20079 分钟前
虚拟机桥接模式
linux·运维·桥接模式
1LOVESJohnny13 分钟前
Linux | scp指令基于WSL在Windows/Ubuntu系统间传输文件
linux·ubuntu·wsl·文件传输
vvw&35 分钟前
如何在 Ubuntu 22.04 上安装 Graylog 开源日志管理平台
linux·运维·服务器·ubuntu·开源·github·graylog
大哥_ZH39 分钟前
Linux umami在国产麒麟系统安装网站统计工具(只能上国内网站的系统)
linux·服务器
o(╥﹏╥)1 小时前
在 Ubuntu 上安装 VS Code
linux·运维·vscode·ubuntu·vs
不爱学英文的码字机器1 小时前
[Linux] Shell 命令及运行原理
linux·运维·服务器
cdut_suye2 小时前
Linux工具使用指南:从apt管理、gcc编译到makefile构建与gdb调试
java·linux·运维·服务器·c++·人工智能·python
qq_433618442 小时前
shell 编程(三)
linux·运维·服务器
Tlzns2 小时前
Linux网络——UDP的运用
linux·网络·udp