对于非亲缘关系的进程间使用共享内存的方式进行通信一般有两种情况:
1.内存映射文件 2.共享内存区对象
对于内存映射文件来说,参考mmap详解,其一般步骤为:
fd = open() ptr= mmap(fd,...)对于后者来说,其一般步骤为:
1.创建或打开一个新的共享内存区对象(shm_open()) 2.用mmmp将这个文件映射到调用进程的空间。
共享内存区对象这个抽象的概念,创建于虚拟文件系统,通常挂在/dev/shm目录中,当我们创建一个共享内存区对象后,可以直接ls /dev/shm查看。
涉及的函数不多,但是非亲缘关系的进程间进行通信,则要考虑同步问题。
创建和删除IPC对象。
#include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ int shm_open(const char *name, int oflag, mode_t mode); int shm_unlink(const char *name); Link with -lrt.关于shm_open的参数 第二个参数:oflag 可以是 O_CREAT|O_EXCL|O_RDWR(这个套路已经很多次了,如果IPC对象存在,则O_EXCL|O_CREAT会返回一个Segment Fault。 第三个参数:mode 可以是0644
调整共享内存区的大小。
#include <unistd.h> #include <sys/types.h> int ftruncate(int fd, off_t length);第一个参数:文件描述符 第二个参数:修改后的大小
两个进程,共享内存区,客户端不停往buffer里面放东西,服务端输出共享内存区的内容(消费)。两个进程通过Posix共享内存区进行通信,使用Posix信号量和Phtread Mutex进行同步。
头文件
//shm.h #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #include <fcntl.h> /* For O_* constants */ #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <semaphore.h> #include <time.h> #include <assert.h> #include <errno.h> #include <signal.h> #include <pthread.h> #define MESGSIZE 256 #define NMESG 16 struct shmstruct{ //这里既可以用二值信号量也可以用互斥锁(需要设置互斥锁属性,否则会死锁) pthread_mutex_t mutex; // sem_t mutex; sem_t nempty; sem_t nstored; int nput; long noverflow; sem_t noverflowmutex; /* mutex for noverflow counter */ long msgoff[NMESG]; /* offset in shared memory of each message */ char msgdata[NMESG * MESGSIZE]; /* the actual messages */ };服务端
//shmserver.c #include "shm.h" int main(int argc,char **argv) { int fd, index, lastnoverflow, temp; long offset; struct shmstruct *ptr; int flag = O_RDWR|O_CREAT|O_EXCL; if (argc != 2) { printf("usage: server2 <name>\r\n"); return -1; } shm_unlink(argv[1]); fd = shm_open(argv[1],O_RDWR|O_CREAT|O_EXCL,0644);//创建共享内存区 ptr=mmap(NULL,sizeof(struct shmstruct),PROT_READ|PROT_WRITE,MAP_SHARED,fd,0);// ftruncate(fd,sizeof(struct shmstruct));//调整大小 close(fd); for (index = 0; index < NMESG; index++)//计算数据的偏移量 ptr->msgoff[index] = index * MESGSIZE; //初始化 pthread_mutexattr_t attr; pthread_mutexattr_init(&attr); pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);//进程间通信需要该属性,否则会死锁 pthread_mutex_init(&ptr->mutex,&attr); // sem_init(&ptr->mutex, 1, 1); sem_init(&ptr->nempty, 1, NMESG); sem_init(&ptr->nstored, 1, 0); sem_init(&ptr->noverflowmutex, 1, 1); index =0; lastnoverflow=0; for(;;) { sem_wait(&ptr->nstored);//同步 pthread_mutex_lock(&ptr->mutex); // sem_wait(&ptr->mutex); offset=ptr->msgoff[index];//获取偏移量 printf("index = %d: %s\n", index, &ptr->msgdata[offset]); if (++index >= NMESG) index = 0; /* circular buffer */ pthread_mutex_unlock(&ptr->mutex); // sem_post(&ptr->mutex); sem_post(&ptr->nempty); sem_wait(&ptr->noverflowmutex);//这里为了计算超出buffer后还发送了多少内容(有多少内容丢失) temp = ptr->noverflow; /* don't printf while mutex held */ sem_post(&ptr->noverflowmutex); if (temp != lastnoverflow) { printf("noverflow = %d\n", temp); lastnoverflow = temp; } } return 0; }客户端
#include "shm.h" int main(int argc,char**argv) { int fd, i, nloop, nusec; pid_t pid; char mesg[MESGSIZE]; long offset; struct shmstruct *ptr; if (argc != 4) printf("usage: client2 <name> <#loops> <#usec>"); nloop = atoi(argv[2]); nusec = atoi(argv[3]); fd = shm_open(argv[1],O_RDWR,0644); ptr = mmap(NULL,sizeof(struct shmstruct),PROT_READ|PROT_WRITE, MAP_SHARED,fd,0); close(fd); pid=getpid(); for(i=0;i<nloop;i++) { snprintf(mesg, MESGSIZE, "pid %ld: message %d", (long) pid, i); if(sem_trywait(&ptr->nempty)==-1) { if(errno==EAGAIN) { sem_wait(&ptr->noverflowmutex);//表示已经满了 ptr->noverflow++; sem_post(&ptr->noverflowmutex); continue; } else { printf("try wait error\r\n"); } } pthread_mutex_lock(&ptr->mutex); //sem_wait(&ptr->mutex); offset = ptr->msgoff[ptr->nput]; if (++(ptr->nput) >= NMESG) ptr->nput = 0; /* circular buffer */ pthread_mutex_unlock(&ptr->mutex); //sem_post(&ptr->mutex); strcpy(&ptr->msgdata[offset],mesg); sem_post(&ptr->nstored); } return 0; }Makefile
PROGS =Client Server CLEANFILES = core core.* *.core *.o temp.* *.out typescript* \ *.lc *.lh *.bsdi *.sparc *.uw all :${PROGS} CFLAGS+=-g LIBS+=-lpthread -lrt Client: shmclient.o ${CC} ${CFLAGS} ${LIBPATH} $^ -o $@ ${LIBS} @rm *.o Server: shmserver.o ${CC} ${CFLAGS} ${LIBPATH} $^ -o $@ ${LIBS} @rm *.o clean: rm -f ${PROGS} ${CLEANFILES}