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结果
read.c结果
二个字:完美!