linux进程间通信—共享内存
共享内存:
(一)共享内存时进程间通信方式最简单之一,共享内存允许两个及两个以上的进程访问同一块内存。就如同malloc()函数向不同进程返回了指向同一个物理内存区域的指针,当一个进程改变这个指针所指向的内容时,其他进程也会察觉到这个改变。
(二)共享内存的特点:
1.共享内存时进程间共享数据的一种最快的方法。当一个进程向共享内存区域写入了数据,共享个内存区域的其他进程就可以立即查看其中的内容。
2.使用共享内存要注意多个进程堆一个存储区访问的互斥。如果一个进程向共享内存去写数据,则在它做完这一步操作前,别的进程不应当去读,写这些数据。
(三)常用函数
1.创建共享内存
(1)所需头文件
#include <sys/ipc.h>
#include <sys/shm.h>
(2)int shmget(key_t key, size_t size, int shmflg);//功能时创建或者打开一块共享内存区
(3)参数:
- key:进程间通信键值,ftok()的返回值
- size:该共享内存区的长度(字节)
- shmflg:标识函数的行为及共享内存的权限,取值如下
- IPC_CREAT:如果不存在就创建
- IPC_EXCL:如果已经存在则返回失败
- 位或权限位:共享内存位或权限位后可以设置共享内存的访问权限
- 返回:
- 成功:共享内存标识符
- 失败:-1
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#define BUFSZ 1024
int main()
{
int shmid;
key_t key;
key = ftok("./",2019);
if(key == -1)
{
perror("ftok error");
}
shmid = shmget(key,BUFSZ,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
exit(-1);
}
return 0;
}
可以看到多了一个共享内存区
2.共享内存映射
(1)所需头文件:
#include <sys/type.h>
#include <sys/shm.h>
(2)void* shmat(int shmid,const void* shmaddr,int shmflg);//将一个共享内存段映射到调用进程的数据段中。即让进程和共享内存建立一种联系,让进程某个指针指向共享内存
(3)参数
-
shmid:共享内存标识符,shmget()的返回值
-
shmaddr:共享内存映射地址,一般使用NULL
-
shmflg:共享内存段的访问权限和映射条件(通常为0)具体取值如下:
-
0:共享内存具有可读可写权限
-
SHM_RDONLY:只读
-
SHM_RND:(shmaddr非空才有效)
(4)返回值:
- 成功:共享内存映射段地址(相当于这个指针就指向次共享内存)
-
失败:-1
3.解除共享内存映射
(1)所需头文件
#include <sys/type.h>
#include <sys/shm.h>
(2)int shmdt(const void* shmaddr);//将共享内存和当前进程分离,但不删除共享内存,相当于让之前的指向此共享内存的指针不指向这里。
(3)参数:
- shmaddr:共享内存映射地址
(4)返回值: - 成功:0
- 失败:-1
4.共享内存控制
(1)所需的头文件:
#include <sys/ipc.h>
#include <sys/shm.h>
(2)int shmctl(int shmid,int cmd,struct shmid_ds* buf);//共享内存属性的控制
(3)参数
- shmid:共享内存标识符
- cmd:函数功能的控制,其取值如下:
- IPC_RMID:删除(常用)。
- IPC_SET:设置shmid_ds参数,相当于把共享内存原来的属性值替换为buff里的属性值。
- IPC_STAT:保存shmid_ds参数,把共享内存原来的属性值备份到buf里。
- SHM_LOCK:锁定共享内存段(超级用户);用于锁定内存,禁止内存交换,并不代表共享内存被锁定后禁止与其他进程建立联系,真正的意义是:被锁定的内存不允许被交换到虚拟内存中,这样做的优势在于让共享内存一直处于内存中,从而提高程序性能。
- SHM_UNLOCK:解锁共享内存段
- buf:shmid_ds数据类型的地址,用来存放或修改共享内存的属性。
(4)返回值:
- 成功:0
- 失败:-1
(四)实战
创建一个A进程,在A进程中创建一个共享内存,并向其写入数据,再创建一个B进程,通过B进程从共享内存中读取数据。
write.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUFSZ 512
int main()
{
key_t key;
int shmid;
//创建key值
key = ftok("/",2019);
if(key == -1)
{
perror("ftok error");
}
//创建共享内存
shmid = shmget(key,BUFSZ,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
exit(-1);
}
//映射
char* shmadd = "123";
shmadd =(char*) shmat(shmid,NULL,0);
if(shmadd <(char*)0)
{
perror("shmat error");
}
//拷贝数据到共享内存区
printf("strcpy");
bzero(shmadd,BUFSZ);
strcpy(shmadd,"hello world");
return 0;
}
read.c
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#define BUFSZ 512
int main()
{
key_t key;
int shmid;
int ret;
//创建key值
key = ftok("/",2019);
if(key == -1)
{
perror("ftok error");
}
//查看共享内存
system("ipcs -m");
//打开共享内存
shmid = shmget(key,BUFSZ,IPC_CREAT|0666);
if(shmid<0)
{
perror("shmget error");
exit(1);
}
//映射
fflush(stdout);
char* shmadd =(char*)shmat(shmid,NULL,0);
//读共享内存区数据
printf("%s\n",shmadd);
//分离共享内存和当前进程
ret = shmdt(shmadd);
if(ret<0)
{
perror("delete false");
}
else
{
printf("delete success");
}
//删除共享内存
shmctl(shmid,IPC_RMID,NULL);
//查看共享内存
system("ipcs -m");
return 0;
}
运行结果如下: