【linux】进程间通信(二)

小小小汐- 2024-10-16 12:37:01 阅读 66

 

6. 命名管道

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

(一)创建一个命名管道

命令行上创建

mkfifo + 管道名

函数调用

int mkfifo(const char *filename,mode_t mode)

filename:

文件名

mode:

权限

代码

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

匿名管道由pipe函数创建并打开 ;命名管道由mkfifo函数创建,打开用openFIFO(命名管道)与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

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

注意:

IPC_EXCL不单独使用

更详细讲 参数key

key是一个数字,它在内核中具有唯一性,能让不同的进程进行唯一性标识第一个进程可以通过key创建共享内存,第二个进程只要拿着key,就能找到和第一个进程访问一样的共享内存对于一个已经创建好的共享内存,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

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

(三)共享内存的特性

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

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

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

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

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,0的“计数器”叫做 二元信号量 -------- 本质就是一个锁申请信号量,本质是对计数器减减,即P操作;释放信号量,本质是对计数器加加,即V操作申请和释放都是原子的(即要么做完,要么不做)信号量本质上也是一种共享资源,所以要先保护好自己,才能对别的临界资源进行保护信号量也是进程通信的一种:通信不仅仅是通信数据,互相协同也是



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。