1. 概述
共享内存,顾名思义就是多个进程共享一块内存区域,在这一块内存区域上进行进程间通信。共享内存更加快速、更加方便,但效率高的同时,也带来了不便。当多个进程使用共享内存进行通信时,由于同时读写了一块共享内存,内存中的数据就会造成混乱,所以同步这个问题就需要特别注意。
2. 共享内存相关操作
共享内存就是通过两个或者多个进程共享同一块内存区域来实现进程间的通信。存放在共享内存中的数据是任何进程都可以对其进行读取的。多个进程可以直接对共享内存中的数据进行操作,因此应用共享内存实现的进程间通信是最快速的,但是多个进程同时读写某一块共享内存时,会造成共享内存中数据的混乱。
接下来通过几个共享内存的操作函数,熟悉如何使用共享内存实现进程间的通信。
2.1 shmget()函数
在使用共享内存实现进程间通信时,需要首先调用shmget()函数创建一块共享内存区域,如果已经存在了一块共享内存区,那么,该函数可以打开此区域。
该函数的定义如下:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmget(key_t key, size_t size, int shmflg);
key:共享内存的名字。
size:共享内存区域的大小,用字节表示。
shmflg:用于设置共享内存的访问权限,也表示调用函数的操作类型。
该函数如果调用成功,返回值是与参数key相关的共享内存区域的标识符;如果调用失败,则返回-1.
2.2 shmat()函数
shmat()函数的功能是将共享内存区域附加到指定的进程地址空间中,定义如下:
#include <sys/types.h>
#include <sys/shm.h>
void* shmat(int shmid,const void* shmaddr, int shmflg);
shmid:共享内存的标识符。
shmaddr:指定进程的内存地址。
shmflg:表示该函数的操作方式
如果shmat()函数调用成功,则返回指向该共享内存区域的指针;如果调用失败,则返回值-1.
2.3 shmdt()函数
shmdt()函数的功能是当某一进程不再使用该内存区域时,将使用shmat()函数附加的共享内存区域从该进程的地址空间中分离出来,定义如下:
#include <sys/types.h>
#include <sys/shm.h>
int shmdt(const void* shmaddr);
该函数调用成功时,返回值为0;如果调用失败,返回值-1.
参数shmaddr为调用shmat()函数附加成功时返回的地址指针。该函数主要实现从shmaddr指针所指的地址空间中分离出此共享内存区域,但此共享内存区域仍然存在。
2.4 shmctl()函数
shmctl()函数主要实现了对共享内存区域的多种控制操作,该函数的定义形式如下:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds* buf);
shimd: 由shmget()函数返回的共享内存标识码;
cmd:将要采取的动作;
buf:一个指向shmid_ds结构体类型的指针。
命令 | 说明 |
---|---|
IPC_STAT | 把shmid_ds结构体中的数据设置为共享内存的当前关联值 |
IPC_SET | 在进程有足够权限的前提下,把共享内存的当前关联值设置为shmid_ds数据结构中给出的值 |
IPC_RMID | 删除shmid标识符所指向的共享内存区域 |
3. 共享内存实现进程间通信
在Linux系统中,使用shmget()函数创建一个共享内存区域,在这个共享内存区域中写入“This is the common data!”,然后在父子进程中分别读取共享内存中的数据,进而实现进程间的数据交换操作。代码如下:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main()
{
int shmid;
int proj_id;
key_t key;
int size;
char* addr;
pid_t pid;
key = IPC_PRIVATE;
shmid = shmget(key,1024, IPC_CREAT|0660); /*创建共享内存*/
if(shmid == -1)
{
perror("create share memory failed!\n");
return 1;
}
addr = (char*)shmat(shmid, NULL, 0); /*将共享内存连接到进程地址空间*/
if(addr == (char*)(-1))
{
perror("cannot attach!\n");
return 1;
}
printf("share memory segment's address: %x\n",addr);
strcpy(addr, "This is the common data!");
pid = fork();
if(pid == -1)
{
perror("fork error!\n");
return 1;
}
else if(pid == 0)
{
printf("child process string is : %s\n", addr);
_exit(0);
}
else
{
wait(NULL); /*等待子进程退出,NULL意思是退出状态不关注。*/
printf("parent process string is : %s\n", addr);
if(shmdt(addr) == -1)
{
perror("release error!\n");
return 1;
}
if(shmctl(shmid, IPC_RMID, NULL) == -1)
{
perror("failed!\n");
return 1;
}
}
return 0;
}
结果: