进程间通讯之共享内存
共享内存是两个或多个进程共享一给定的在内存上的存储区。进程之间共享这个存储区,所以,数据的存取就减少了复制的过程,这就使得共享内存成为一种最快的IPC。另外,这部分共享存储区被作为一个临界资源,则用信号量来实现共享存储区访问的同步。即当一进程正在使用这一存储区,并在他完成这一操作之前,其它进程应不能访问这部分存储区。
共享内存的操作:
创建获取:
int shmget((ket_t)key, size_t size, int flag);
key:创建标识
size:内存区大小(字节)
flag:创建权限
成功返回存储区ID(shmid),失败返回 -1
映射到本进程的地址空间上:
void *shmat(int shmid, void *addr, int flag);
shmid:内存区ID
*addr:指定链接地址
flag:权限
成功返回内存区地址,失败返回 -1
断开链接:
int shmdt(void *ptr);
*ptr:指向内存区首地址的指针
成功返回0,失败返回 -1
释放:
int shmctl(int shmid, int cmd, struct shmid_ds *buff);
cmd:命令参数(IPC_STAT IPC_SET IPC_RMID SHM_LOCK SHM_UNLOCK)
shmid_ds:内核为共享存储区分配的一个结构
工作原理为:
可以看出进程操作共享存储区是通过指针来实现的。
下面就是具体的实现代码:
首先用信号量来对共享内存进行控制:
头文件:sem.h
#ifndef __SEM_H
#define __SEM_H
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>
#include<assert.h>
#include <sys/sem.h>
#include <sys/shm.h>
union semun
{
int val;
};
void sem_get();
void sem_p();
void sem_v();
void sem_del();
#endif
信号量控制的实现:
#include "sem.h"
int semid = -1;
void sem_get() // 创建或者获取信号量集。
{
semid = semget((key_t)1234, 1, 0664);
if(semid == -1)
{
semid = semget((key_t)1234, 1, IPC_CREAT | 0664);
if(semid == -1)
{
perror("");
exit(0);
}
// 初始化新创建的信号量集
union semun un;
un.val = 1;
semctl(semid, 0, SETVAL, un);
}
}
void sem_p() // 完成P操作
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = -1;
buf.sem_flg = SEM_UNDO;
semop(semid, &buf, 1);
}
void sem_v() // 完成V操作
{
struct sembuf buf;
buf.sem_num = 0;
buf.sem_op = 1;
buf.sem_flg = SEM_UNDO;
if(-1 == semop(semid, &buf, 1))
{
perror("");
}
}
void sem_del() // 释放信号量集
{
semctl(semid, 0, IPC_RMID);
}
A进程实现从内存中读数据:
#include "sem.h"
int main()
{
int shmid = shmget((key_t)1234, 128, IPC_CREAT|0664);
assert(shmid != -1);
char *ptr = (char*)shmat(shmid, NULL, 0);
sem_get();
while(1)
{
sem_p();
if(strncmp(ptr, "end", 3) == 0)
{
break;
}
printf("%s \n %d\n", ptr, strlen(ptr) - 1);
sem_v();
}
shmdt(ptr);
exit(0);
}
B进程实现向内存中写数据:
#include "sem.h"
int shmid = shmget((key_t)1234, 128, IPC_CREAT|0664);
assert(shmid != -1);
char *ptr = (char*)shmat(shmid, NULL, 0);
sem_get();
while(1)
sem_p();
printf("please input: ");
fgets(ptr, 128, stdin);
sem_v();
if(strncmp(ptr, "end", 3) == 0)
{
break;
}
}
shmdt(ptr);