与信号量相类似,通常需要在包含shm.h文件之前包含sys/types.h与sys/ipc.h这两个头文件。
IPC操作时IPC_CREAT和IPC_EXCL选项的说明
IPC(包括消息队列,共享内存,信号量)的xxxget()创建操作时,可以指定IPC_CREAT和IPC_EXCL选项。
以共享内存为例:
当只有IPC_CREAT选项打开时,不管是否已存在该块共享内存,则都返回该共享内存的ID,若不存在则创建共享内存;
当只有IPC_EXCL选项打开时,不管有没有该快共享内存,shmget()都返回-1;
当IPC_CREAT | IPC_EXCL时, 如果没有该块共享内存,则创建,并返回共享内存ID。如果已存在,则立即返回-1,不会打开或者创建。(通常用来判断那个进程首先被打开,然后让其初始化,以后打开的进程就无需对共享内存初始化了)
demo:
利用IPC对象的共享内存机制,实现两个进程通信,用信号同步。
//writer.c #include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <errno.h> #include <sys/ipc.h> #include <sys/types.h> #include <sys/shm.h> #include <string.h> #define N 1024 typedef struct { pid_t pid; //最先打开的进程会把自己的pid记录在此,对其进行初始化 char buf[N]; }SHM; void handler(int signo) //用于发给唤醒pause { } int main() { key_t key; int shmid; SHM *shmaddr; pid_t peerpid; signal(SIGUSR1, handler); if ((key = ftok(".", 'a')) == -1) { perror("ftok"); exit(-1); } //创建共享内存 if ((shmid = shmget(key, sizeof(SHM), 0666 | IPC_CREAT | IPC_EXCL)) == -1)//IPC_EXCL同open的EXCL,用于判断是哪个进程最先打开 { if (errno == EEXIST) { shmid = shmget(key, sizeof(SHM), 0666); if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) { perror("shmat"); exit(-1); } peerpid = shmaddr->pid; shmaddr->pid = getpid(); kill(peerpid, SIGUSR1); } else { perror("shmget"); exit(-1); } } else //first { if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)//添加映射 { perror("shmat"); exit(-1); } shmaddr->pid = getpid(); pause(); peerpid = shmaddr->pid; } while (1) { fgets(shmaddr->buf, N, stdin); kill(peerpid, SIGUSR1); if (strncmp(shmaddr->buf, "quit", 4) == 0) break; pause(); } if (shmdt(shmaddr) == -1) //解除映射 { perror("shmdt"); exit(-1); } if (shmctl(shmid, IPC_RMID, NULL) == -1)//释放共享内存 { perror("RM"); exit(-1); } exit(0); }
//reader.c #include <stdio.h> #include <unistd.h> #include <signal.h> #include <stdlib.h> #include <errno.h> #include <sys/ipc.h> #include <sys/types.h> #include <sys/shm.h> #include <string.h> #define N 1024 typedef struct { pid_t pid; char buf[N]; }SHM; void handler(int signo) { } int main() { key_t key; int shmid; SHM *shmaddr; pid_t peerpid; signal(SIGUSR1, handler); if ((key = ftok(".", 'a')) == -1) { perror("ftok"); exit(-1); } if ((shmid = shmget(key, sizeof(SHM), 0666 | IPC_CREAT | IPC_EXCL)) == -1) { if (errno == EEXIST) { shmid = shmget(key, sizeof(SHM), 0666); if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) { perror("shmat"); exit(-1); } peerpid = shmaddr->pid; shmaddr->pid = getpid(); kill(peerpid, SIGUSR1); } else { perror("shmget"); exit(-1); } } else //first { if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) { perror("shmat"); exit(-1); } shmaddr->pid = getpid(); pause(); peerpid = shmaddr->pid; } while (1) { pause(); printf("%s", shmaddr->buf); if (strncmp(shmaddr->buf, "quit", 4) == 0) break; kill(peerpid, SIGUSR1); } if (shmdt(shmaddr) == -1) { perror("shmdt"); exit(-1); } exit(0); }