1 #include<sys/types.h> 2 #include<sys/ipc.h> 3 #include<sys/sem.h> 4 #include <stdio.h> 5 #include <stdlib.h> 6 #include<errno.h> 7 8 int gSemid = 0; 9 typedef int sem_t; 10 #define ERR_EXIT(m) \ 11 do \ 12 { \ 13 perror(m); \ 14 exit(EXIT_FAILURE); \ 15 }while(0) 16 17 sem_t CreateSem(key_t key, int initValue, int semNum) 18 { 19 union semun sem; 20 sem_t semid; 21 sem.val = initValue; 22 23 semid = semget(key, 5, IPC_CREAT | IPC_EXCL | 0666);//创建信号量个数为1 24 if(-1 == semid) 25 { 26 ERR_EXIT("semget"); 27 } 28 for(int i=0;i<semNum;i++) 29 { 30 semctl(semid, i, SETVAL, sem);//参数2-要操作的信号量在信号量集中的编号;参数3-cmd... 31 } 32 return semid; 33 } 34 35 int Sem_P(sem_t semid) 36 { 37 //sops有三种方式,0-默认阻塞、IPC_NOWAIT-非阻塞、SEM_UNDO-撤销上一次操作 38 struct sembuf sops={0,-1,0}; 39 return (semop(semid,&sops,1)); 40 } 41 42 int Sem_V(sem_t semid) 43 { 44 struct sembuf sops={0,+1,0}; 45 return (semop(semid,&sops,1)); 46 } 47 48 void SetvalueSem(sem_t semid, int value) 49 { 50 union semun sem; 51 sem.val = value; 52 53 semctl(semid,0,SETVAL,sem); 54 } 55 56 int GetvalueSem(sem_t semid) 57 { 58 union semun sem; 59 return semctl(semid,0,GETVAL,sem); 60 } 61 62 void DestroySem(sem_t semid) 63 { 64 union semun sem; 65 sem.val = 0; 66 semctl(semid,0,IPC_RMID,sem); 67 } 68 69 void Print(char opChar) 70 { 71 int pauseTime; 72 srand(getpid()); 73 int i; 74 75 for(i=0; i<10; i++) 76 { 77 if(Sem_P(gSemid) != 0) 78 ERR_EXIT("Sem_P"); 79 //临界区-begin 80 printf("%c", opChar); 81 fflush(stdout); 82 pauseTime = rand()%3; 83 sleep(pauseTime); 84 printf("%c", opChar); 85 fflush(stdout); 86 //临界区-end 87 Sem_V(gSemid); 88 pauseTime = rand()%2; 89 sleep(pauseTime); 90 } 91 } 92 #define DELAY (rand()%5+1) 93 94 void waitFor2Fork(int phiNum) 95 { 96 int ret = 0; 97 int left = phiNum;//哲学家左侧 筷子编号 98 int right = (phiNum+1)%5; 99 struct sembuf buf[2] = { 100 {left, -1, 0}, 101 {right, -1, 0} 102 }; 103 //同时拿起左侧右侧的筷子,则不会发生死锁 104 //如果没有被释放,则等待 105 ret = semop(gSemid, buf, 2); 106 if(-1 == ret) 107 { 108 ERR_EXIT("waitFor2Fork"); 109 } 110 } 111 void free2Fork(int phiNum) 112 { 113 int left = phiNum;//哲学家左侧 筷子编号 114 int right = (phiNum+1)%5; 115 struct sembuf buf[2] = { 116 {left, +1, 0}, 117 {right, +1, 0} 118 }; 119 //同时放下筷子 120 semop(gSemid, buf, 2); 121 } 122 123 void waitForLeftFork(int phiNum) 124 { 125 int ret = 0; 126 int left = phiNum;//哲学家左侧 筷子编号 127 int right = (phiNum+1)%5; 128 struct sembuf buf = {left, -1, 0}; 129 //同时拿起左侧右侧的筷子,则不会发生死锁 130 //如果没有被释放,则等待 131 ret = semop(gSemid, &buf, 1); 132 if(-1 == ret) 133 { 134 ERR_EXIT("waitForLeftFork"); 135 } 136 } 137 void waitForRightFork(int phiNum) 138 { 139 int ret = 0; 140 int left = phiNum;//哲学家左侧 筷子编号 141 int right = (phiNum+1)%5; 142 struct sembuf buf = {right, -1, 0}; 143 //同时拿起左侧右侧的筷子,则不会发生死锁 144 //如果没有被释放,则等待 145 ret = semop(gSemid, &buf, 1); 146 if(-1 == ret) 147 { 148 ERR_EXIT("waitForRightFork"); 149 } 150 } 151 void freeLeftFork(int phiNum) 152 { 153 int left = phiNum;//哲学家左侧 筷子编号 154 int right = (phiNum+1)%5; 155 struct sembuf buf = {left, +1, 0}; 156 //同时放下筷子 157 semop(gSemid, &buf, 1); 158 } 159 void freeRightFork(int phiNum) 160 { 161 int left = phiNum;//哲学家左侧 筷子编号 162 int right = (phiNum+1)%5; 163 struct sembuf buf = {right, +1, 0}; 164 //同时放下筷子 165 semop(gSemid, &buf, 1); 166 } 167 //#define LOCK 168 void Philosopher(int phiNum) 169 { 170 #ifdef LOCK 171 for(;;)//有锁 172 { 173 printf("%d is thinking\n",phiNum); 174 sleep(DELAY); 175 printf("%d is hungry\n",phiNum); 176 waitFor2Fork(phiNum); 177 printf("%d is eating\n",phiNum); 178 sleep(DELAY); 179 free2Fork(phiNum); 180 } 181 #else 182 for(;;)//无锁 183 { 184 printf("%d is thinking\n",phiNum); 185 sleep(DELAY); 186 printf("%d is hungry\n",phiNum); 187 waitForLeftFork(phiNum); 188 sleep(5); 189 waitForRightFork(phiNum); 190 printf("%d is eating\n",phiNum); 191 sleep(DELAY); 192 freeLeftFork(phiNum); 193 freeRightFork(phiNum); 194 } 195 #endif 196 } 197 198 int main(void) 199 { 200 char i; 201 key_t key; 202 int value = 0; 203 int pid; 204 int phiNum = 0; 205 206 key = ftok("./ipc", 'c'); 207 gSemid = CreateSem(key,1, 5);//5个信号量都初始化为1,表示可用的状态 208 209 for(int i=1; i<5; i++) 210 { 211 pid = fork(); 212 if(-1 == pid) 213 ERR_EXIT("fork"); 214 if(0 == pid)//子进程 215 { 216 phiNum = i; 217 break; 218 } 219 } 220 221 Philosopher(phiNum); 222 223 return 0; 224 }