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 }