拥有梦想是一种智力,实现梦想是一种能力
概述
若是一个多线程的进程,由于各个线程共享一个地址空间,可以直接通过变量的形式进行通信。而进程,由于各个进程独占一个地址空间,我们需要一种通信机制来完成进程间的数据交互。本章介绍的是共享内存,进程间的通信机制有以下几种:
无名管道(pipe)
有名管道 (fifo)
信号(signal)
System V IPC
共享内存(share memory)
消息队列(message queue)
信号灯集(semaphore set)
套接字(socket)
之间有区分与各自的运用场景,其中套接字通常使用在网络服务,其他只能在本地场景下使用。笔者以后会逐一学习,本章介绍System V IPC中的共享内存。
System V IPC
System V IPC引入了三种高级进程间的通信机制。一个IPC对象包含消息队列、共享内寸和信号量。
- 共享内存
- 消息队列
- 信号灯集
System V IPC对象
每个IPC对象有唯一的ID
IPC对象创建后一直存在,直到被显式地删除
每个IPC对象有一个关联的KEY(其中进程的私有对象KTY值为0)
命令查看IPC对象
IPC对象是全局对象,可用ipcs,ipcrm等命令查看或删除
ipcs -q: 只显示消息队列
ipcs -s: 只显示信号量
ipcs -m: 只显示共享内存
ipcs –help: 其他的参数
函数操作
创建一个IPC对象
进程创建IPC对象之前,先ftok生成一个key值。
#include <sys/types.h>
#include <sys/ipc.h>
key_t ftok(const char *path, int proj_id);
- 成功时返回合法的key值,失败时返回EOF
- path 存在且可访问的文件的路径
- proj_id 用于生成key的数字,不能为0
共享内存
特点
- 共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝
- 共享内存在内核空间创建,可被进程映射到用户空间访问,使用灵活
- 由于多个进程可同时访问共享内存,因此需要同步和互斥机制配合使用
共享内存使用步骤
- 创建/打开共享内存
- 映射共享内存,即把指定的共享内存映射到进程的地址空间用于访问
- 读写共享内存
- 撤销共享内存映射
- 删除共享内存对象
shmget 创建共享内存
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, int size, int shmflg);
- 成功时返回共享内存的id,失败时返回EOF
- key 和共享内存关联的key,IPC_PRIVATE 或 ftok生成
- shmflg 共享内存标志位 IPC_CREAT|0666
shmat 共享内存映射
#include <sys/ipc.h>
#include <sys/shm.h>
void *shmat(int shmid, const void *shmaddr, int shmflg);成功时返回映射后的地址,失败时返回(void *)-1
shmid 要映射的共享内存id
shmaddr 映射后的地址, NULL表示由系统自动映射
shmflg 标志位 0表示可读写;SHM_RDONLY表示只读
共享内存读写
通过指针访问共享内存,指针类型取决于共享内存中存放的数据类型
例如char *addr;
int shmid;
……
if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1) {//映射
perror(“shmat”);
exit(-1);
}
fgets(addr, N, stdin);//从终端读数据到内存
shmdt撤销映射
#include <sys/ipc.h>
#include <sys/shm.h>
int shmdt(void *shmaddr);
- 成功时返回0,失败时返回EOF
- 不使用共享内存时应撤销映射
- 进程结束时自动撤销
shmctl内存控制
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
- 成功时返回0,失败时返回EOF
- shmid 要操作的共享内存的id
- cmd 要执行的操作 IPC_STAT IPC_SET IPC_RMID
- buf 保存或设置共享内存属性的地址
如果要删除内存
shmctl(shmid, IPC_RMID, NULL) 添加删除标记,nattach 变成0时真正删除
示例
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
key_t key;
char *addr;
int shmid;
if ((key = ftok(“.”, ‘a’)) == -1)
{
perror(“key”);
exit(-1);
}
if ((shmid = shmget(key, 1024, IPC_CREAT|0666)) < 0)
{
perror(“shmget”);
exit(-1);
}
if ((addr = (char *)shmat(shmid, NULL, 0)) == (char *)-1)
{
perror(“shmat”);
exit(-1);
}
fgets(addr, N, stdin);
shmdt(addr);
shmctl(shmid, IPC_RMID, NULL);
return 0;
}