进程间通信 共享内存

什么是共享内存

共享内存,顾名思义就是允许两个不相关的进程访问同一个逻辑内存,共享内存是两个正在运行的进程之间共享和传递数据的一种非常有效的方式。共享存储允许两个或多个进程共享一个给定的存储区。因为数据不需要在客户进程和服务器进程之间复制,直接在内存上操作,所以共享内存的速度也就提高了。所以这是最快的一种IPC。

因为共享内存是将同一内存映射到他们的地址空间,所有进程共享同一块内存,共享内存在各种进程间通信方式中具有最高的效率,使用时最好加上同步机制比如信号量。

共享内存操作流程

①进程间通信标识KEY值的生成:ftok函数生成键值

②shmget函数创建共享内存空间

③shmat函数获取第一个可用共享内存空间的地址

④shmdt函数进行分离(对共享存储段操作结束时的步骤,并不是从系统中删除共享内存和结构)

⑤shmctl函数进行删除共享存储空间

共享内存API

shmget

int shmget(key_t key, size_t size, int shmflg): 创建共享内存 ——获得共享存储标识符

key:键值。

size:共享存储段长度,以字节为单位。

shmflg:如果要创建新的共享内存,需要使用IPC_CREAT,IPC_EXCL以及权限。

shmat

void *shmat(int shmid, const void *shmaddr, int shmflg):关联共享内存

创建后还不能马上使用,需要连接到进程的地址空间。

shm_id:是由shmget函数返回的共享内存标识。

shm_addr:指定共享内存连接到当前进程中的地址位置,通常为空,表示让系统来选择共享内存的地址。

shm_flg:是一组标志位,通常为0。具体参数详解可参考(《UNIX环境高级编程》)

返回值:出错返回-1,成功返回该段所连接的实际地址。

shmdt

int shmdt(const void *shmaddr) : 进程与共享存储段shmaddr分离

shmaddr以前调用shmat时的返回值。

shmctl

int shmctl(int shmid, int cmd, struct shmid_ds *buf);: 操作共享内存(大多为销毁)cmd设置为IPC_RMID时表示可以删除共享内存。

cmd:采取操作使其在shmid指定的段上执行,如下三个参数。

IPC_STAT:把shmid_ds结构中的数据设置为共享内存的当前关联值,即用共享内存的当前关联值覆盖struct shmid_ds *buf的值。

IPC_SET:如果进程有足够的权限,就把共享内存的当前关联值设置为struct shmid_ds *buf结构中给出的值

IPC_RMID:删除共享内存段

buf: 若cmd为IPC_RMID,则可以将最后一位设置为0。

信号量+共享内存(同步)代码

jc1.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{
	void *shmadd;
	struct sembuf set;
	int *t;
	key_t key=ftok("jc2.c",0);
	key_t shm_key=ftok("jc1.c",0);
	printf("key:%d\n",key);
	int sem_id=semget(key,1,IPC_CREAT|0666);
	if(sem_id<0)
	{
		perror("semget");
		printf("create error!\n");
	}else{
		printf("create successfullyftok\n");
	}
	if(semctl(sem_id,0,SETVAL,1))
		printf("set val error\n");

	set.sem_num=0;
	set.sem_op =-1;
	set.sem_flg=SEM_UNDO;
	if(!semop(sem_id,&set,1))
	{
	int shm_id=shmget(shm_key,sizeof(int),IPC_CREAT|IPC_EXCL|0666);
	printf("%d\n",shm_id);
	if(shm_id<0)
		perror("shmget");
	shmadd=shmat(shm_id,0,0);
	if(shmadd<0)
	perror("shmat");
	t=(int*)shmadd;
	*t=3;
	int val=semctl(sem_id,0,GETVAL,0);
        printf("val=%d\n",val);
	
	shmdt(shmadd);
	}else	
		perror("semop");
	set.sem_num=0;
        set.sem_op =1;
        set.sem_flg=SEM_UNDO;
	semop(sem_id,&set,1);
	printf("write over\n");
}
jc2.c
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <sys/ipc.h>
#include <sys/shm.h>

int main()
{
	void *shmadd;
	struct sembuf set;
	int *t;

	key_t key=ftok("jc2.c",0);
	key_t shm_key=ftok("jc1.c",0);
	printf("key:%d\n",key);/**/
	
	int sem_id=semget(key,0,0666);/*获取已有的信号量*/
	printf("%d\n",sem_id);
	if(sem_id<0)
	{
		perror("semget");
		printf("create error!\n");
	}else{
		printf("create successfullyftok\n");
	}
	
	

	int val=semctl(sem_id,0,GETVAL,0);/*查看信号量值*/
        printf("val=%d",val); 
	set.sem_num=0;
	set.sem_op =-1;
	set.sem_flg=0;
	if(!semop(sem_id,&set,1))/*请求信号量控制资源*/
	{
	int shm_id=shmget(shm_key,0,0666);/*打开已有的共享内存段*/
	if(shm_id<0)
		perror("shmget");
	shmadd=shmat(shm_id,0,0);/*挂载共享内存段到进程地址空间*/
	if(shmadd<0)
	perror("shmat");
	t=(int*)shmadd;
	printf("this is t:%d\n",*t);
	shmdt(shmadd);/*与shmadd分离*/
	shmctl(shm_id,IPC_RMID,0);/*删除共享内存段,其实这里可以加个判断共享内存段的连接计数是否为0,若为0,则删除共享内存*/
	
	}else	
		perror("semop");
	
	set.sem_num=0;
    set.sem_op =1;
    set.sem_flg=SEM_UNDO;
	semop(sem_id,&set,1);/*释放所占资源*/
	
	printf("read over\n");
	if(semctl(sem_id,0,IPC_RMID))/*删除此信号量集*/
                perror("semctl");

}

结果

结果

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值