完成的功能:一个进程负责将键盘输入的内容写到共享内存,另一个进程负责将共享内存中的数据输出到屏幕上。
两个进程通过pause和kill实现同步。首先运行的进程将自己的pid存到共享内存,然后pause,等待另一个进程将从共享内存中读到的pid保存,然后写入自己的pid后,被对方唤醒。
最后,收到quit命令的进程负责删除共享内存。
writeshm.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <sys/ipc.h> 6 #include <string.h> 7 #include <signal.h> 8 #include <sys/shm.h> 9 #include <errno.h> 10 #include <unistd.h> 11 12 #define N 1024 13 typedef struct 14 { 15 pid_t pid; 16 char text[N]; 17 }SHM; 18 19 void handler(int signo) {} 20 21 int main() 22 { 23 key_t key; 24 int shmid; 25 SHM *shmaddr; 26 struct shmid_ds buf; 27 pid_t peerpid; 28 29 signal(SIGUSR1, handler); 30 31 if ((key = ftok(".", 97)) == -1) 32 { 33 perror("fork"); 34 exit(-1); 35 } 36 37 if ((shmid = shmget(key, sizeof(SHM), IPC_CREAT | 0666 | IPC_EXCL)) > 0) //不存在创建,存在报错EEXIS 38 { 39 printf("first run\n"); 40 if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1)//首先运行,得到共享内存映射后的地址 41 { 42 perror("shmat"); 43 exit(-1); 44 } 45 shmaddr->pid = getpid(); //将直接的pid存入共享内存 46 pause(); //进入sleep状态,等待被另一个进程发信号唤醒 47 peerpid = shmaddr->pid; //保存对方的pid 48 } 49 else 50 { 51 if (errno == EEXIST) //说明是第二个运行的 52 { 53 printf("last run\n"); 54 shmid = shmget(key, sizeof(SHM), 0666); //得到共享内存的id 55 if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) 56 { 57 perror("shmat"); 58 exit(-1); 59 } 60 peerpid = shmaddr->pid; //将共享内存中的pid保存起来,就是对方的pid 61 shmaddr->pid = getpid(); //将自己的pid存入共享内存 62 kill(peerpid, SIGUSR1); //唤醒对方 63 } 64 else 65 { 66 perror("shmget"); 67 exit(-1); 68 } 69 } 70 printf("peerpid=%d\n", peerpid); 71 72 while (1) 73 { 74 printf(">"); 75 fgets(shmaddr->text, N, stdin); //将键盘输入的内容存入共享内存 76 kill(peerpid, SIGUSR1); //唤醒对方 77 if (strncmp(shmaddr->text, "quit", 4) == 0) 78 break; 79 pause(); //等待被对方唤醒 80 } 81 82 if (-1 == shmdt(shmaddr)) //解除映射 83 { 84 perror("shmdt"); 85 exit(-1); 86 } 87 /* 88 if (-1 == shmctl(shmid, IPC_STAT, &buf)) //查询共享内存的状态 89 { 90 perror("shmctl stat"); 91 exit(-1); 92 } 93 if (buf.shm_nattch == 0) //如果共享内存没有 94 { 95 if (-1 == shmctl(shmid, IPC_RMID, NULL)) 96 { 97 perror("shmctl rm"); 98 exit(-1); 99 } 100 } 101 */ 102 return 0; 103 }
readshm.c
1 #include <stdio.h> 2 #include <stdlib.h> 3 #include <sys/types.h> 4 #include <sys/stat.h> 5 #include <sys/ipc.h> 6 #include <string.h> 7 #include <signal.h> 8 #include <sys/shm.h> 9 #include <errno.h> 10 #include <unistd.h> 11 12 #define N 1024 13 typedef struct 14 { 15 pid_t pid; 16 char text[N]; 17 }SHM; 18 19 void handler(int signo) {} 20 21 int main() 22 { 23 key_t key; 24 int shmid; 25 SHM *shmaddr; 26 struct shmid_ds buf; 27 pid_t peerpid; 28 29 signal(SIGUSR1, handler); 30 31 if ((key = ftok(".", 97)) == -1) 32 { 33 perror("fork"); 34 exit(-1); 35 } 36 37 if ((shmid = shmget(key, sizeof(SHM), IPC_CREAT | 0666 | IPC_EXCL)) > 0) //不存在创建,存在报错EEXIS 38 { 39 printf("first run\n"); 40 if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) 41 { 42 perror("shmat"); 43 exit(-1); 44 } 45 shmaddr->pid = getpid(); 46 pause(); 47 peerpid = shmaddr->pid; 48 } 49 else 50 { 51 if (errno == EEXIST) 52 { 53 printf("last run\n"); 54 shmid = shmget(key, sizeof(SHM), 0666); 55 if ((shmaddr = (SHM *)shmat(shmid, NULL, 0)) == (SHM *)-1) 56 { 57 perror("shmat"); 58 exit(-1); 59 } 60 peerpid = shmaddr->pid; 61 shmaddr->pid = getpid(); 62 kill(peerpid, SIGUSR1); 63 } 64 else 65 { 66 perror("shmget"); 67 exit(-1); 68 } 69 } 70 printf("peerpid=%d\n", peerpid); 71 72 while (1) 73 { 74 pause(); //等待对方写入 75 sleep(1); 76 printf("%s", shmaddr->text); 77 if (strncmp(shmaddr->text, "quit", 4) == 0) 78 break; 79 kill(peerpid, SIGUSR1); //唤醒对方 80 } 81 82 if (-1 == shmdt(shmaddr)) //解除映射 83 { 84 perror("shmdt"); 85 exit(-1); 86 } 87 88 if (-1 == shmctl(shmid, IPC_STAT, &buf)) //查询共享内存的状态 89 { 90 perror("shmctl stat"); 91 exit(-1); 92 } 93 if (buf.shm_nattch == 0) //如果共享内存的映射数为0,则删除共享内存 94 { 95 if (-1 == shmctl(shmid, IPC_RMID, NULL)) 96 { 97 perror("shmctl rm"); 98 exit(-1); 99 } 100 } 101 102 return 0; 103 }