大家好,我是练习时长两年半的练习生,喜欢唱、跳、rap、敲代码,键来!
在前面我们已经讲过,早期的进程间通信有三种——无名管道、有名管道、信号,(传送门:Linux C 进程间的通信——无名管道、有名管道、信号),今天就来浅谈一下在system V IPC的三种对象,也是进程通信的另外三种姿势——共享内存、消息队列、信号量。
目录
一、共享内存
(一)概念
共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝。为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将其映射到自己的私有地址空间,进程就可以直接读写这一内存区而不需要进行数据的拷贝,从而大大提高进程通信的效率。
(二)基操
1》创建或者获取共享内存
2》将共享内存映射到用户空间
3》解除映射
4》删除共享内存
(三)相关API
1. 创建密钥 ftok
注意!!!
只要pathname和proj_id不变,就可以获得相同的key,如下,进程A和进程B获得的key相同。
例子:
进程A:key_t key1=ftok("xx.txt",0xa);
进程B:key_t key2=ftok("xx.txt",0xa);
#include <sys/types.h>
#include <sys/ipc.h>
/**
***********************************
*@brief 创建密钥key
*@param pathname:带路径的文件名
proj_id:数字
*@retval key_t
成功返回key
失败返回-1,并返回错误码EOF
***********************************
*/
key_t ftok(const char *pathname, int proj_id);
2. 创建共享内存 shmget
#include <sys/ipc.h>
#include <sys/shm.h>
/**
***********************************
*@brief 创建或者获取共享内存
*@param key:密钥
IPC_PRIVATE:系统自动分配key
size:共享内存的大小
shmflg:权限,一般写为 IPC_CREAT|0666
*@retval int
成功返回共享内存的id
失败返回-1,并返回错误码EOF
***********************************
*/
int shmget(key_t key, size_t size, int shmflg);
3. 共享内存映射到用户空间 shmat
#include <sys/types.h>
#include <sys/shm.h>
/**
***********************************
*@brief 将共享内存映射到用户空间
*@param shmid:共享内存的id
shmaddr:需要映射到什么地方(地址)
shmflg:访问权限
SH_RDONLY:只读
0:默认,可读可写
*@retval int
成功返回映射后的地址
失败返回-1,并返回错误码EOF
***********************************
*/
void *shmat(int shmid, const void *shmaddr, int shmflg);
4. 解除映射 shmdt
#include <sys/types.h>
#include <sys/shm.h>
/**
***********************************
*@brief 解除映射
*@param shmaddr:需要解除映射的地址
*@retval int
成功返回0
失败返回-1,并返回错误码EOF
***********************************
*/
int shmdt(const void *shmaddr);
5. 管理共享内存 shmctl
#include <sys/ipc.h>
#include <sys/shm.h>
/**
***********************************
*@brief 删除
*@param shmid:需要解除映射的地址
cmd:IPC_STAT (获取对象属性)
IPC_SET (设置对象属性)
IPC_RMID (删除对象)
buf:如果cmd为IPC_RMID,则此处置NULL
*@retval int
成功返回0
失败返回-1,并返回错误码EOF
***********************************
*/
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
struct shmid_ds {
struct ipc_perm shm_perm; /* Ownership and permissions */
size_t shm_segsz; /* Size of segment (bytes) */
time_t shm_atime; /* Last attach time */
time_t shm_dtime; /* Last detach time */
time_t shm_ctime; /* Last change time */
pid_t shm_cpid; /* PID of creator */
pid_t shm_lpid; /* PID of last shmat(2)/shmdt(2) */
shmatt_t shm_nattch; /* No. of current attaches */
...
};
(四)示例代码
shm_write.c 和 shm_read.c代码基本一样,代表两个不同的进程,一个写入一个读取。shm_write.c中每次输入一行数据就会覆盖原来在共享内存空间的数据,输入quit退出输入状态,然后解除映射删除空间。shm_read.c读取到quit后也会退出,然后解除映射。
shm_write.c:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys