Linux进程通信 共享内存

1.概述

共享内存是进程通信的一种方式。此方式会开辟一部分可以被多个进程共享访问的物理内存区域。进行通信的多个进程分别将该内存区域映射到自己的虚拟地址空间,则这些进程就可直接访问共享内存,从而达到通信的目的。这种方法进程间共享数据时最快,一个进程修改共享内存的数据后,其他进程可以立即看到。

2 通信步骤

头文件

#include<sys/ipc.h>

#include<sys/shm.h>

<1>创建共享内存

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

Shmget()用来取得参数key所关联的共享内存标识号。若key为IPC_PRIVATE则会创建新的共享内存,大小有size决定。若key不为IPC_PRIVATE,也不是已建立的共享内存,则会根据shmflg决定。

参数:key 0/IPC_PRIVATE

size 内存大小

shmflg 旗标位

返回值:成功返回共享内存识别id,失败返回-1,错误存储在errno中

<2>连接到共享内存

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

shmat()用来将参数shmid所指的共享内存和目前的进程连接。

参数:shmid 与连接的共享内存标识码

shmaddr  0 内核自动选择一个地址

shmaddr  不为0且shmflg未指定SHM_RND,以shmaddr为连接地址

shmaddr 不为0但shmflg指定SHM_RND,shmaddr会调整为SHMLBA整数倍

返回值:成功返回已连接地址,失败返回-1,错误存储在errno中

<4>断开连接

int shmdt(const void *shmaddr);

shmdt()使当前进程与共享内存断开连接

参数:shmaddr为先前shmat()返回的共享内存地址

返回值 成功返回0,失败返回-1,错误存储在errno中

<3>对共享内存进行操作

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

shmctl()提供了几种控制共享内存的方式

参数:shmid 为共享内存的标识码

cmd 如下

IPC_STAT 得到共享内存的状态,

IPC_SET 改变共享内存的状态

IPC_RMID 删除共享内存

struct shmid_ds *buf是一个结构体指针。IPC_STAT的时候,取得的状态放在这个结构体中。如果要改变共享内存的状态,用这个结构体指定。

返回值 成功返回0,失败返回-1,错误存储在errno中

 

举例

创建一个共享内存,子进程写入HelloWorld,由父进程读出

 

  1. #include<sys/types.h>
  2. #include<sys/ipc.h>
  3. #include<sys/shm.h>
  4. #include<stdio.h>
  5. #include<sys/stat.h>
  6. #include<stdlib.h>
  7. #define KEY 1234
  8. #define SIZE 2048
  9. int main()
  10. {
  11.   pid_t pid;
  12.   int shmid; /*共享内存ID*/
  13.   char * shmaddr; /*连接地址*/
  14.   struct shmid_ds buf;
  15.   shmid=shmget(KEY,SIZE,IPC_CREAT|0600);/*建立共享内存*/
  16.   pid=fork();
  17.   if(pid<0)
  18.    {
  19.      perror(“fork error!\n”);
  20.     exit(0);
  21.    }
  22.   if(pid==0)/*子进程将”Hello world!\n写入共享内存”*/
  23.   {
  24.     shmaddr=shmat(shmid,NULL,0);/*子进程与共享内存连接*/
  25.     sprintf(shmaddr,”Hello world!\n”);/*写入共享内存*/
  26.     printf(“Messgae have been write to shared memory!\n”);
  27.     shmdt(shmaddr);/*断开子进程与共享内存的连接*/
  28.     exit(0);
  29.    }
  30.    sleep(3);/*待子进程结束*/
  31.    shmctl(shmid,IPC_STAT,&buf);/*共享内存状态存入buf中*/
  32.    shmaddr=(char *)shmat(shmid,NULL,0);/*父进程与共享内存连接*/
  33.    printf(“Message in shared memory:%s\n”,shmaddr);/*输出共享内存数据*/
  34.    shmdt(shmaddr);/*断开父进程与共享内存的连接*/
  35.    shmctl(shmid,IPC_RMID,NULL);/*删除共享内存*/
  36. }

输出

Messgae have been write to shared memory!
Message in shared memory:Hello world!

另外也可重新创建一个进程,读取该共享内存的数据。将上个c文件中最后一行删除,使得程序结束时不删除共享内存,再执行下面程序,使新进程读取共享内存数据。(共享内存需一致,创建时KEY相同)

 

  1. #include<sys/types.h>
  2. #include<sys/ipc.h>
  3. #include<sys/shm.h>
  4. #include<stdio.h>
  5. #include<sys/stat.h>
  6. #include<stdlib.h>
  7. #define KEY 1234
  8. #define SIZE 2048
  9. int main()
  10. {
  11.   pid_t pid;
  12.   int shmid; /*共享内存ID*/
  13.   char * shmaddr; /*连接地址*/
  14.   struct shmid_ds buf;
  15.   shmid=shmget(KEY,SIZE,IPC_CREAT|0600);/*建立共享内存*/
  16.    shmctl(shmid,IPC_STAT,&buf);/*共享内存状态存入buf中*/
  17.    shmaddr=(char *)shmat(shmid,NULL,0);/*进程与共享内存连接*/
  18.    printf(“Message in shared memory:%s\n”,shmaddr);/*输出共享内存数据*/
  19.    shmdt(shmaddr);/*断开进程与共享内存的连接*/
  20.    shmctl(shmid,IPC_RMID,NULL);/*删除共享内存*/
  21. }

$ ipcs -m

—— Shared Memory Segments ——–
key        shmid      owner      perms      bytes      nattch     status
0×00068520 65538      root      666        2352       16
0×00068521 98307      root      666        624        13
0x0006c650 131076     nobody    666        408        11
0x0006c620 163845     root      666        81056      0
0x0006c766 196614     nobody    666        264        7
0x0006c6af 229383     root      666        408        11
0x0006c709 262152     root      666        264        7
其中:
key: shmget第一个参数
owner: 为共享内存的所有者
perms: 权限
bytes: 共享内存的大小
通过key找到自己程序创建的共享内存, 发现owner确实和程序运行的时候的身份不一致
怎么手动删除一个共享内存呢?
通过rpcrm -m shmid删除一个已经存在的共享内存
假如我们要删除key=0x0006c709 shmid=262152的共享内存,可以使用下面的命令完成:
ipcrm -m  262152

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>