41.Linux 共享内存

本文详细介绍了如何使用IPC(Inter-Process Communication)中的共享内存进行进程间通信。从shmget函数创建共享内存对象,ftok生成key,到shmat将内存映射到用户空间,再到shmdt解除映射和shmctl删除内存,最后展示了父子进程及无亲缘关系进程间的通信实例。内容涵盖了共享内存的基本操作及其在实际通信中的应用。
摘要由CSDN通过智能技术生成

                                                IPC和文件IO函数的比较 

文件I/OIPC
open

Msg_get

Shm_get

Sem_get

read

write

msgsnd  msgrecv

shmat     shmdt

semop

close

msgctrl

shmctrl

semctrl

打开或创建一个共享内存对象,共享内核在内核是什么样子的?

一块缓存,变类似于用户空间的数组或malloc函数分配的空间一样

所需头文件

#include <sys/types.h>

#include <sys/ipc.h>

#include <sys/shm.h>

函数原型int shmget(key_t key,int size,int shmflg);
函数参数key:IPC_PRIVATE(私有的)或ftok的返回值
size:共享内存区大小
shmflg:同open函数的权限位,也可以用8进制表示法
函数返回

成功:共享内存段标识符——ID——文件描述符

失败:-1

查看IPC对象      ipcs      -m(共享内存)         -q(消息队列)       -s(信号灯)

删除IPC对象      ipcrm   -m   id

返回值:共享内存段标识符        IPC的ID 号

通过程序来理解shmget函数的用法(第一个IPC_PRIVATE来获得)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
	int shmid;
	shmid=shmget(IPC_PRIVATE,128,0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	system("ipcs -m");
	//system("ipcrm -m shmid");
	return 0;
}

执行结果如下:

通过IPC_PRIVATE创建的宏key始终等于0.,可以实现有亲缘关系之间的通信

shmget类似文件IO中的open函数,会在内核中创建一个对象,我们称之为共享内存,而共享内存就是一个内核中的缓存,这个缓存就像是一个数组。 

①key:第一个IPC_PRIVATE来获得,第二个通过ftok函数的返回值获得

②大小:

③权限

2.ftok函数:创建key的值。

char ftok(const char *path,char key);

参数:第一个参数:文件路径和文件名

          第二个参数:  一个字符

返回值:正确返回一个key值,出错返回-1.

ftok函数可以实现无亲缘关系之间的通信。

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
	int shmid;
	key_t key;
	key=ftok("./a.c",'a');
	if(key<0)
	{
		printf("creat key failure\n");
		return -2;
	}
	printf("creat key sucess key=%X\n",key);
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	system("ipcs -m");
	//system("ipcrm -m shmid");
	return 0;
}

执行结果如下:

 发现key值这个时候再也不等于0

IPC_PRAVATE操作时,共享内存的key值都一样,都是0所以使用ftok来创建key值只要key值是一样的,用户空间的进程通信这个函数打开,则会对内核的同一个IPC对象操作。

(3)shmat函数  将共享内存映射到用户空间的地址中

能不能用read,write呢?

为了方便用户空间对共享内存的操作,使用地址映射的方式。

类似于malloc

void *shmat(int shmid,const void *shmaddr,int shmflg);

参数:第一个参数:ID号

           第二个参数:映射到的地址,NULL为系统自动完成的映射;

           第三个参数shmflg:SHM_RDONLY共享内存只读

                                           默认是0,表示共享内存可读写。

返回值:成功:映射后的地址;

失败:NULL。

 程序:shmat的设计

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
int main()
{
	int shmid;
	key_t key;
	char *p;
	key=ftok("./a.c",'a');

	if(key<0)
	{
		printf("creat key failure\n");
		return -2;
	}
	printf("creat key sucess key=%X\n",key);
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	system("ipcs -m");
	
	p=(char *)shmat(shmid,NULL,0);
	if(p==NULL)
	{
		printf("shmat function failure\n");
		return -3;
	}
	fgets(p,128,stdin);

	//start read_share_memory
	printf("share memory data:%s\n",p);

	return 0;
}

  执行后的结果为:

 共享内存的特点:

-共享内存创建后,一直存在于内核中,直到被删除或系统关闭

-共享内存和管道不一样,读取后,内容仍在其共享内存中。

不过用完了共享内存之后,就释放

(4)shmdt:将用户空间进程里的地址映射删除

int shmdt(const void *shmaddr);

参数:shmaddr共享内存映射后的地址

返回值:成功:0

              失败:-1  

shmdt函数的用法

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main()
{
	int shmid;
	key_t key;
	char *p;
	key=ftok("./a.c",'a');

	if(key<0)
	{
		printf("creat key failure\n");
		return -2;
	}
	printf("creat key sucess key=%X\n",key);
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	system("ipcs -m");
	
	p=(char *)shmat(shmid,NULL,0);
	if(p==NULL)
	{
		printf("shmat function failure\n");
		return -3;
	}
	fgets(p,128,stdin);

	//start read_share_memory
	printf("share memory data:%s\n",p);
	
	printf("second share memory data:%s\n",p);

	shmdt(p);
	memcpy(p,"abcd",4);

	return 0;
}

执行结果如下:

 发生段错误,因为内存已经被释放

(5)shmctl函数:删除内核空间共享内存对象

函数原型:int shmctl(int shmid,int cmd,struct shmid_ds *buf);

函数参数:shmid:要操作的共享内存标识符

                  cmd:IPC_STAT(获取对象属性)——实现了命令ipcs -m

                            IPC_SET(设置对象属性)                          

                            IPC_RMID(删除对象)      ——实现了命令ipcrm  -m  

                  buf:指定IPC_STAT/IPC_SET时用于保存/设置属性

函数返回值:成功:0

                      失败:-1    

ipcs -m:查看内核空间共享内存对象

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main()
{
	int shmid;
	key_t key;
	char *p;
	key=ftok("./a.c",'a');

	if(key<0)
	{
		printf("creat key failure\n");
		return -2;
	}
	printf("creat key sucess key=%X\n",key);
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	system("ipcs -m");
	
	p=(char *)shmat(shmid,NULL,0);
	if(p==NULL)
	{
		printf("shmat function failure\n");
		return -3;
	}
	fgets(p,128,stdin);

	//start read_share_memory
	printf("share memory data:%s\n",p);
	
	printf("second share memory data:%s\n",p);

	shmdt(p);
	
	shmctl(shmid,IPC_RMID,NULL);
	system("ipcs -m");
	return 0;
}

执行结果如下:

 共享内存被删除了

使用我们前面学到的知识构建ipcs -m和ipcrm -m这两个命令

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
int main(int argc,char *argv[])
{
	int shmid;
	if(argc<3)
	{
		printf("please input param\n");
		return -1;
	}	
	if(strcmp(argv[1],"-m")==0)
		printf("delete share memory ");
	else
		return -2;
	shmid=atoi(argv[2]);
	printf("shmid=%d\n",shmid);
	shmctl(shmid,IPC_RMID,NULL);	
	system("ipcs -m");
	return 0;
}

执行结果如下:

父子进程之间的共享内存通信(IPC_PRIVATE)

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
void myfunc(int signum)
{
	return;
}
int main()
{
	int shmid;
	char *p;
	pid_t pid;
	shmid=shmget(IPC_PRIVATE,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	
	pid=fork();
	if(pid>0)
	{
		signal(SIGUSR2,myfunc);
		p=(char *)shmat(shmid,NULL,0);
		if(p==NULL)
		{
			printf("parent process : shmat function failure\n");
			return -3;
		}
		while(1)
		{
			printf("parent process start write share memory:\n");
			fgets(p,128,stdin);
			kill(pid,SIGUSR1);//child process read data
			pause();//wait child process read
		}
	}
	if(pid==0)//child process
	{
		signal(SIGUSR1,myfunc);
		p=(char *)shmat(shmid,NULL,0);
		if(p==NULL)
		{
			printf("child process : shmat function failure\n");
			return -3;
		}
		while(1)
		{
			pause();//wait parent process write
			//start read_share_memory
			printf("share memory data:%s\n",p);
			kill(getppid(),SIGUSR2);
		}
	}

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	system("ipcs -m");
	return 0;
}

执行结果如下:

 

无亲缘关系进程之间的通信(必须使用ftok函数),server.c发送信号,client.c接收信号

server.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
struct mybuf{
	int pid;
	char buf[124];
};

void myfunc(int signum)
{
	return;
}
int main()
{
	int shmid;
	struct mybuf *p;
	int key;
	pid_t pid;
	key=ftok("./a.c",'a');
	if(key<0)
	{
		printf("creat key failure\n");
		return -1;
	}
	printf("creat key sucess\n");
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	
	

		signal(SIGUSR1,myfunc);
		p=(struct mybuf *)shmat(shmid,NULL,0);
		if(p==NULL)
		{
			printf("parent process : shmat function failure\n");
			return -3;
		}
		//get server pid
		//read share memory
		pid=p->pid;
		//write client pid to share memory
		p->pid=getpid();
		//kill signal
		kill(pid,SIGUSR2);

		//client start read data from share memory
		while(1)
		{
			pause();//wait server write data to share memory;
			printf("client process receive data from share memory:%s",p->buf);//read data
			kill(pid,SIGUSR2);//server may write share memory
		}
	

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	system("ipcs -m");
	return 0;
}

client.c

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/ipc.h>
#include <signal.h>
#include <unistd.h>
#include <string.h>
struct mybuf{
	int pid;
	char buf[124];
};

void myfunc(int signum)
{
	return;
}
int main()
{
	int shmid;
	struct mybuf *p;
	int key;
	pid_t pid;
	key=ftok("./a.c",'a');
	if(key<0)
	{
		printf("creat key failure\n");
		return -1;
	}
	printf("creat key sucess\n");
	shmid=shmget(key,128,IPC_CREAT|0777);
	if(shmid<0)
	{
		printf("creat share memory failure\n");
		return -1;
	}
	printf("creat share memory sucess shmid=%d\n",shmid);
	
	

		signal(SIGUSR2,myfunc);
		p=(struct mybuf *)shmat(shmid,NULL,0);
		if(p==NULL)
		{
			printf("parent process : shmat function failure\n");
			return -3;
		}
		//get client pid
		p->pid=getpid();//write server pid to share memory
		
		pause();//wait client read server pid;

		pid=p->pid;

		//write
		while(1)
		{
			printf("parent process start write share memory:\n");
			fgets(p->buf,128,stdin);
			kill(pid,SIGUSR1);//client process read data
			pause();//wait client process read
		}
	

	shmdt(p);
	shmctl(shmid,IPC_RMID,NULL);
	system("ipcs -m");
	return 0;
}

执行结果如下:

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值