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

时间:2021-09-05 05:17:23

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实现


二个字:完美!