共享内存的概念:<没有同步与互斥机制,生命周期随内核>
共享内存就是两个或多个进程占有一段内存空间,同一块物理内存空间被映射到两个进程,两个进程都可以访问这段共享空间,从而实现了进程间通信,但其只有数据交换的功能,并没有提供同步与互斥机制。
共享内存是最快的ipc形式。一旦这样的内存映射到共享它的进程的地址空间,这些进程间数据传递不涉及到内核。
共享内存区进程间的数据传递:
(1).用户空间到内存。
(2).内存到用户空间。
下图是共享内存的结构:
共享内存的数据结构:
struct shmid_ds{
struct ipc_perm shm_perm;//IPC对象数据结构
int shm_segsz;//共享内存的字节数
_kernel_time_t shm_atime;//最后一次映射的时间
_kernel_time_t shm_dtime;//最后一次脱离的时间
_kernel_time_t shm_ctime; //最后一次更动此共享内存的时间。
_kernel_ipc_pid_t shm_cpid; // 建立此共享内存的进程识别码。
_kernel_ipc_pid_t shm_lpid;// 最后一个操作此共享内存的进程识别码。
unsigned short shm_nttach; /* no. of current attaches */
unsigned short shm_unused;/* compatibility */
void *shm_unused2;/* ditto - used by DIPC */
void *shm_unused3;/* unused */
};
共享内存函数:
shmget函数:
功能:用来创建共享内存。
函数原型:
int shmget(key_t key,size_t size,int shmflg);
参数:
- key:共享内存段的名字。
- size:共享内存的大小。
- shmflg:由9个权限标志组成,它们的用法和创建文件时使用的mode 模式标志是一样的。
返回值:成功返回一个非负整数,即该共享内存段的标识码;失败返回-1。
shmat函数:
功能:将共享内存段连接到进程地址空间。
原型:
void *shmat(int shmid,const void *shmaddr,int shmflg);
参数:
- shmid:共享内存标识
- shmaddr:指定连接的地址
- shmflg:取值为SHM_RND和SHM_RONLY
返回值:成功返回一个指针,指向共享内存第一个节;失败返回-1.
说明:
1. shmaddr为NULL,核心自动选择一个地址。
2. shmaddr不为NULL且shmflg无SHM_RND标记,则以shmaddr为连接地址。
3. shmaddr不为NULL且shmflg设置了SHM_RND标记,则连接的地址会自动向下调整为SHMLBA的整数倍。
公式:shmaddr-(shmaddr%SHMLBA)
4.shmflg=SHM_RONLY,表示连接操作用来只读共享内存。
shmdt函数:
功能:将共享内存段与当前进程脱离。
原型:
int shmdt(const void *shmaddr);
参数:
shmaddr:由shmat返回的指针。
返回值:成功返回0,失败返回-1.
将共享内存段与当前进程脱离不等于删除共享内存段
shmctl函数:
#include <sys/ipc.h>
#include <sys/shm.h>
int shmctl(int shmid, int cmd, struct shmid_ds *buf);
返回值:如果操作成功返回0,否则返回-1。
各参数的含义如下:
(1)参数shmid
参数shmid表示需要操作的共享内存标识符,也就是shmget函数的返回值。
(2)、参数cmd
参数cmd指明了所要进行的操作类型,主要有以下五种:
cmd取值 | 操作类型 |
---|---|
IPC_STAT | 取该共享内存的shmid_ds结构,并存在第三个参数中 |
IPC_SET | 使用buf指定的结构设置相关属性 |
IPC_RMID | 删除指定共享内存,只有当buf中的shm_nattch值为0时才真正删除 |
IPC_LOCK | 在内存中对共享内存加锁(超级用户权限) |
IPC_UNLOCK | 解锁共享内存(超级用户权限) |
参数buf:指向一个保存着共享内存的模式状态和访问权限的数据结构。
具体代码实现如下:
common.h
1 #pragma once
2 #include<stdio.h>
3 #include<sys/ipc.h>
4 #include<sys/shm.h>
5 #include<sys/types.h>
6
7 #define PATHNAME "."
8 #define PROJ_ID 0x6666
9
10 int commonshm(int size,int flags);
11 int createshm(int size);
12 int getshm(int size);
13 int destoryshm(int shmid);
common.c
#include"common.h"
2 int commonshm(int size,int flags)
3 {
4 key_t key=ftok(PATHNAME,PROJ_ID);
5 if(key<0){
6 perror("ftok()");
7 return -1;
8 }
9 int shmid=shmget(key,size,flags);
10 if(shmid<0){
11 perror("shmget()");
12 }
13 return shmid;
14 }
15 int createshm(int size)
16 {
17 return commonshm(size,IPC_CREAT|IPC_EXCL|0666);
18 }
19 int getshm(int size)
20 {
21 return commonshm(size,IPC_CREAT);
22 }
23 int destoryshm(int shmid)
server.c:
1 #include"common.h"
2 int main()
3 {
4 int shmid=createshm(1024);
5 char*ptr=(char*)shmat(shmid,NULL,0);
6 int i=0;
7 while(1){
8 printf("client# %s\n",ptr);
9 ptr[i]='A';
10 ptr[++i]='\0';
11 sleep(1);
12 sleep(1);
13 }
14 shmdt(ptr);
15 sleep(1);
16 destroyshm(shmid);
17 return 0;
18 }
client.c
#include"common.h"
2 int main()
3 {
4 int shmid=getshm(1024);
5 char*ptr=(char*)shmat(shmid,NULL,0);
6 int offset=0;
7 //while(1){
8 // printf("server# %s\n",ptr);}
9 while(1){
10 printf("server# %s\n",ptr);
11 int count=0;
12 char*cur=ptr;
13 for(;count<10;++count){
14 *cur++='A'+offset;
15 sleep(1);
16 }
17 *cur='\0';
18 ++offset;
19 offset%=26;
20 }
21 sleep(1);
22 shmdt(ptr);
23 return 0;
24 }
因为共享内存没有同步与互斥机制,若要实现双向通信。则需用两个共享内存区。
如:A->B,A只能写数据,B只能读数据。
B->A,B只能写数据,A只能读数据。