IPC之共享内存
共享内存作为IPC(Inter-Process Communication)的一种方式,适合同一台机器上不同进程间的相互通信,由于不同进程直接对同一块"约定好"的内存进行操作,因此效率为所有IPC中最高的。
共享内存的使用还是很简单的,主要涉及到五个函数的使用,下面一一进行介绍。
(1)key_t ftok(const char *pathname, int proj_id);
功能:用来创建System V IPC的一个key值
参数:pathname:系统中真实存在的并可以访问的目录或文件
proj_id :在1~255之间的数值,可以用来标识这是该进程创建的第几块共享内存
返回值:成功则返回一个key_t值;失败返回-1.
(2)int shmget(key_t key, size_t size, int shmflg);
功能:用来创建一块共享内存
参数: key :由ftok返回的值
size :需要创建共享内存的大小
shmflg:共享内存的模式及权限标识
模式可以取如下值:
IPC_CREAT: 新建一块共享内存
IPC_ALLOC: 使用已开辟的内存
IPC_EXCL : 如果标识符已存在,则返回错误值
返回值:成功则返回一个标志值;失败返回-1.
(3)void *shmat(int shmid, const void *shmaddr, int shmflg);
功能:把由shmid标识的共享内存attach到该进程的地址空间
参数: shmid :由shmget返回的共享内存的标志
shmaddr :把共享内存attach在进程地址空间的起始地址,一般设为0
shmflg :进程对该内存的操作模式。SHM_RDONLY表示只读模式,其它为读写模式。
返回值:成功则返回一个共享内存起始地址;失败返回(void *)-1.
(4)int shmdt(const void *shmaddr);
功能:删除一块共享内存
参数: shmaddr :要从进程中detach的共享内存地址
返回值:成功则返回0;失败返回-1.
(5) int shmctl(int shmid, int cmd, struct shmid_ds *buf);
功能:执行对共享内存的控制
参数: shmid :标志共享内存的id
cmd :控制命令,可取值如下:
IPC_STAT :得到共享内存的状态
IPC_SET :改变共享内存的状态
IPC_RMID :删除共享内存
buf :用来存放共享内存的状态
返回值:失败返回-1;成功返回其他值。
下面看两个使用共享内存通信进程的例子:
1 //process1.cc 2 3 #include <stdio.h> 4 #include <errno.h> 5 #include <string.h> 6 #include <sys/shm.h> 7 #include <sys/ipc.h> 8 9 #define MAX_SHM_SIZE 1024*1024 10 11 int main(int argc, char *argv[]) 12 { 13 const char *name = "/home/pathenon/project/network"; 14 int i = 1; 15 16 key_t key = ftok(name, i); 17 if(-1 == key) 18 { 19 perror("ftok"); 20 return 1; 21 } 22 23 int shm_id=shmget(key, MAX_SHM_SIZE, IPC_CREAT|0666); 24 if(-1 == shm_id) 25 { 26 perror("shmget"); 27 return 1; 28 } 29 30 char buffer[] = "Hello share memory ipc\n"; 31 char *p = (char *)shmat(shm_id, 0, 0); 32 if((void *)-1 == (void *)p) 33 { 34 perror("shmat"); 35 return 1; 36 } 37 38 //write memory 39 int size = sizeof(buffer); 40 memcpy(p, &size, 4); 41 memcpy(p+4, buffer, sizeof(buffer)); 42 43 shmdt(p); 44 45 return 0; 46 }
1 //process2.cc 2 3 #include <stdio.h> 4 #include <errno.h> 5 #include <string.h> 6 #include <sys/shm.h> 7 #include <sys/ipc.h> 8 9 #define MAX_SHM_SIZE 1024*1024 10 11 int main() 12 { 13 const char *name = "/home/pathenon/project/network"; 14 int i = 1; 15 16 key_t key = ftok(name, i); 17 if(-1 == key) 18 { 19 perror("ftok"); 20 return 1; 21 } 22 23 int shm_id=shmget(key, MAX_SHM_SIZE, IPC_CREAT|0666); 24 if(-1 == shm_id) 25 { 26 perror("shmget"); 27 return 1; 28 } 29 30 char *p = (char *)shmat(shm_id, 0, 0); 31 if((void *)-1 == (void *)p) 32 { 33 perror("shmat"); 34 return 1; 35 } 36 37 //read memory 38 int size; 39 memcpy(&size, p, 4); 40 char buffer[1024] = {'\0'}; 41 memcpy(buffer, p+4, size); 42 43 printf("%s", buffer); 44 45 shmdt(p); 46 47 return 0; 48 }
分别编译上面两个程序,并先运行第一个可执行程序,后运行第二个,会发现输出:Hello share memory ipc
我们可以总结一下使用共享内存的大致步骤:
1.使用ftok获得一个key_t值
2.使用 shmget()开辟一块共享内存
3.使用shmat()允许本进程使用某块共享内存
4.对共享内存进行操作
5.禁止本进程使用这块共享内存 shmdt()
6.使用shmctl()或者命令行下ipcrm删除这块共享内存
注意:在使用完共享内存后,如果没有在程序中用shmctl()删除共享内存就退出程序,一定要在命令行下用ipcrm命令删除这块共享内存否则它就一直在那儿放着。
下面使用ipcs命令和ipcrm命令来查看与删除共享内存。
>ipcs -m
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 65538 yangfan 600 196608 2
>ipcrm -m 65538
------ Shared Memory Segments --------
key shmid owner perms bytes nattch status
0x00000000 65538 yangfan 600 196608 2 dest