linux基于信号量同步的共享内存IPC实现

时间:2021-08-05 15:18:26

linux常见IPC方式有:管道,有名管道,信号量,消息队列,共享内存,socket套接字。共享内存是最快的IPC方式。

本文是具体别称实现共享内存的IPC,一个程序向内存写数据,另一个程序读数据,共享内存牵扯到同步的问题,一般有三种方案可以实现共享资源的同步

信号量,记录锁和互斥量。

       使用信号量,首先服务端创建一个只含一个信号的信号量集合,并初始化为1。占据资源,则以sem_op=-1调用semop函数。释放资源,则则以sem_op=1调用semop函数。

       使用记录锁,需要创建一个文件,并写入一个字节。分配资源,对文件获得写锁,释放资源,解锁。

       使用互斥量,需要所有的进程将相同的文件映射到他们的地址空间,并使用PTHREAD_PROCESS_SHARED互斥量属性在文件中初始化互斥量。分配资源,对互斥量加锁,释放资源,解锁互斥量。

       我是选择使用信号量的同步方式实现共享内存。两个程序write.c和read.c分别如下:

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>//共享存储头文件
#include<stdlib.h>
#include<unistd.h>
#include<sys/sem.h>//利用信号量实现同步功能控制对共享内存的访问
#include<string.h>
#include<sys/stat.h>
#include<fcntl.h>
int main()
{
	void *shm=NULL;//分配的共享内存的首地址

	//利用当前路径,创建key_t
	char ptr[50];
	if(getcwd(ptr,50)==NULL)
		printf("getcwd erro\n");
	printf("cwd=%s\n",ptr);

	//获得信号量
	int sig=semget(IPC_PRIVATE,1,0666|IPC_CREAT);
	if(sig==-1)
		printf("get sem erro\n");
	union semun
	{
		int val;
		struct semid_ds *buf;
		unsigned short *array;
	}arg_sem;
	arg_sem.val=1;
	if(semctl(sig,0,SETVAL,arg_sem)==-1)
		printf("信号量初始化失败\n");
	//分配资源
	struct sembuf sem,fsem;
	sem.sem_num=0;
	sem.sem_op=-1;
	sem.sem_flg=SEM_UNDO;
//	semop(sig,sem,1);
	//释放资源
	fsem.sem_num=0;
	fsem.sem_op=1;
	fsem.sem_flg=SEM_UNDO;
	//创建共享内存
	int shmid;
	shmid=shmget(IPC_PRIVATE,1024,0666);
	if(shmid==-1)
	{
		printf("get a shm erro\n");
		exit(0);
	}
	//将共享内存连接到当前进程的地址上
	shm=shmat(shmid,0,0);
	if(shm==(void *)-1)
		printf("shmat erro\n");
	printf("shm at %X\n",(int)shm);
	char buffer[BUFSIZ+1];//保存输入的文本
	
	//把共享内存,信号量标识符写入文件,以便客户端读取利用  sig  shmid
	FILE* fd;
	if((fd=fopen("log","w"))==NULL)
		printf("创建文件失败\n");
	if(fwrite(&sig,sizeof(int),1,fd)!=1)
		printf("fwrite sig erro\n");
	if(fwrite(&shmid,sizeof(int),1,fd)!=1)
		printf("fwrite shmid erro\n");
	fclose(fd);
	
	printf("sig:%d\n shmid:%d\n",sig,shmid);
	printf("bufsize:%d\n",BUFSIZ);
	char *ch;
	int b=0;
	while(1)
	{
		if(semop(sig,&sem,1)==-1)//分配资源出错
			printf("分配资源出错\n");
		else
		{
			printf("占据资源\n");
			//分配成功,写内存
			printf("Enter some data:");
			fgets(buffer,BUFSIZ,stdin);
			if(strncmp(buffer,"end",3)==0)
				b=1;	

			strncpy(shm,buffer,2048);
			ch=shm;
			while(*ch!='\0')
				printf("%c",*ch),ch++;
			//释放资源
			if(semop(sig,&fsem,1)==-1)
				printf("free sem erro\n");
			printf("释放资源\n");
			if(b)
				break;
		}
		usleep(100);
	}
	return 0;
}

#include<stdio.h>
#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/shm.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/sem.h>
#include<string.h>
#include<sys/stat.h>
#include<string.h>

int main()
{
	//打开文件获取共享内村,信号量标识符
	///
	FILE* fd;
	if((fd=fopen("log","r"))==NULL)
		printf("open fd erro\n");
	//用于同步的信号量标识符
	int sig;
	if(fread(&sig,sizeof(int),1,fd)!=1)
		printf("read sig erro\n");
	int shmid;
	if(fread(&shmid,sizeof(int),1,fd)!=1)
		printf("read shmid erro\n");
	fclose(fd);
	printf("sig :%d\nshmid: %d\n",sig,shmid);
	//引用共享内村连接到当前进程的地址上
	void *shm=NULL;
	shm=shmat(shmid,0,0);
	if(shm==(void *)-1)  
		printf("link shm erro\n");
	//分配与释放内存的配置
	struct sembuf sem,fsem;
	sem.sem_num=0;
	sem.sem_op=-1;
	sem.sem_flg=SEM_UNDO;

	fsem.sem_num=0;
	fsem.sem_op=1;
	fsem.sem_flg=SEM_UNDO;
	char *ch;
		
	struct shmid_ds *buf;
	buf=(struct shmid_ds*)malloc(1);
	if(buf)
		printf("申请成功\n");
	int bb=0;
	while(1)
	{
		//信号量分配资源
		if(semop(sig,&sem,1)==-1)
			printf("分配资源出错\n");
		else
		{
			printf("占据资源\n");
			if(shmctl(shmid,IPC_STAT,buf)==-1)
				printf("erro\n");
			//输出IPC结构
			printf("shm_segsz:%d,shm_lpid:%d,",
				buf->shm_segsz,buf->shm_lpid);
			printf("shm_nattch:%d\n",buf->shm_nattch);

			//读内年数据
			ch=shm;
			if(strncmp(ch,"end",3)==0)
				bb=1;
			while(*ch!='\0')
				printf("%c",*ch),ch++;
			//释放资源
			if(semop(sig,&fsem,1)==-1)
				printf("free sem erro\n");
			printf("释放资源\n");
			if(bb)
				break;
		}
		usleep(100);
	}
	exit(0);
}
gcc 4.6.3编译运行结果:

write.c结果linux基于信号量同步的共享内存IPC实现


read.c结果linux基于信号量同步的共享内存IPC实现


二个字:完美!