Advertisement
SIKER_98

222

Jan 18th, 2020
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.82 KB | None | 0 0
  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 <sys/shm.h>
  7. #include <sys/sem.h>
  8. #include <fcntl.h>
  9. #include <string.h>
  10. #include <signal.h>
  11. #include <unistd.h>
  12. #include <errno.h>
  13.  
  14. //#define _DEBUG
  15. #define BUFSIZE 200
  16.  
  17. #define ODCZYT 0
  18. #define ZAPIS 1
  19. // numery semaforów w zbiorze
  20.  
  21. const char *fnames[4] = { "", "fifo1", "fifo2", "fifo3" };
  22.  
  23. typedef struct
  24. {
  25. int pid[4];
  26. char buf12[BUFSIZE];
  27. char buf23[BUFSIZE];
  28. } mem;
  29. mem *ptr;
  30.  
  31. int shmid;
  32. int sem12, sem23;
  33.  
  34. enum { PRACUJ, CZEKAJ, INIT } stan;
  35.  
  36.  
  37. static void get_sig(int signo)
  38. {
  39. // należy sprawdzić, czy nie jest to pierwsze budenie dzieci ze ¶pi±czki po urodzeniu
  40. // w takim wypadku nic nie musimy dalej robić
  41. if (stan == INIT)
  42. {
  43. stan = PRACUJ;
  44. return;
  45. }
  46. int pnr;
  47. int fs;
  48. int _pid = getpid();
  49. for (pnr = 1; _pid != ptr->pid[pnr] && pnr <= 3; ++pnr);
  50. // ponieważ procedura obsługi sygnałów jest taka sama dla wszystkich procesów
  51. // należy sprawdzić z którym z nich mamy do czynenia
  52. if (pnr == 4)
  53. {
  54. printf("porażka\n");
  55. exit(1);
  56. }
  57.  
  58. #ifdef _DEBUG
  59. printf("%d: Otrzymałem sygnał %d\n", pnr, signo);
  60. #endif
  61.  
  62. // je¶li przyszedł sygnał od operatora
  63. if (signo != SIGUSR2)
  64. {
  65. int i;
  66. for (i = 1; i <= 3; ++i)
  67. // każdemu z rodzeństwa (oprócz sobie) wysyłam komunikat
  68. if (i != pnr)
  69. {
  70. kill(ptr->pid[i], SIGUSR2);
  71. #ifdef _DEBUG
  72. printf("%d: Wysłałem sygnał %d do procesu %d\n", pnr, SIGUSR2, i);
  73. #endif
  74. int f = open(fnames[i], O_WRONLY);
  75. write(f, &signo, sizeof(signo));
  76. close(f);
  77. #ifdef _DEBUG
  78. printf("%d: Zapisałem sygnał %d do kolejki %s\n", pnr, signo, fnames[i]);
  79. #endif
  80. }
  81. }
  82. else
  83. {
  84. // sygnał od rodzeństwa
  85. #ifdef _DEBUG
  86. printf("%d: Prubuję odczytać sygnał ze swojej kolejki\n", pnr);
  87. #endif
  88. fs = open(fnames[pnr], O_RDONLY);
  89. read(fs, &signo, sizeof(signo));
  90. close(fs);
  91. #ifdef _DEBUG
  92. printf("%d: Odczytałem sygnał %d ze swojej kolejki\n", pnr, signo);
  93. #endif
  94. }
  95. #ifdef _DEBUG
  96. printf("%d: Podejmuję stosowne działania zwi±zane z sygnałem %d\n", pnr, signo);
  97. #endif
  98. // każdy proces podejmie teraz akcje zwi±zane z sygnałem wsyłanym przez operatora
  99. if (signo == SIGINT)
  100. {
  101. // poniższe zasoby może posprz±tać tylko jeden proces
  102. if (pnr == 1)
  103. {
  104. shmctl(shmid, IPC_RMID, 0);
  105. semctl(sem12, IPC_RMID, 0);
  106. semctl(sem23, IPC_RMID, 0);
  107. }
  108. // kolejkę fifo każdy proces usuwa sobie sam
  109. unlink(fnames[pnr]);
  110. exit(0);
  111. }
  112. else if (signo == SIGUSR1)
  113. {
  114. stan = CZEKAJ;
  115. }
  116. else if (signo == SIGCONT)
  117. {
  118. stan = PRACUJ;
  119. }
  120. }
  121.  
  122. void wait4pids()
  123. {
  124. pause();
  125. // tu dzieci czekaj± na urodzenie ich wszystkich,
  126. // wpisanie imion i zabicie
  127.  
  128. ptr = (mem *)shmat(shmid, NULL, 0);
  129. if (! ptr)
  130. {
  131. printf("bł±d shmat\n");
  132. exit(1);
  133. }
  134. #ifdef _DEBUG
  135. printf("?: pids: %d, %d, %d, %d\n",
  136. ptr->pid[0], ptr->pid[1], ptr->pid[2], ptr->pid[3]);
  137. #endif
  138. }
  139.  
  140. void sem_down(int semid, int semnum)
  141. {
  142. struct sembuf op;
  143. op.sem_flg = 0;
  144. op.sem_num = semnum; // numer semafora: 0 do odczytu, 1 do zapisu
  145. op.sem_op = -1; // kierunek i warto¶ć: -1 o jedno w dół
  146. do
  147. {
  148. errno = 0;
  149. semop(semid, &op, 1);
  150. }
  151. while (errno == EINTR);
  152. // powodem przekroczenia opuszczonego semafora może być otrzymanie sygnału
  153. // w takim przypadku proces powinien wrócić przed semafor
  154. }
  155.  
  156. void sem_up(int semid, int semnum)
  157. {
  158. struct sembuf op;
  159. op.sem_flg = 0;
  160.  
  161. op.sem_num = semnum;
  162. op.sem_op = 1;
  163. semop(semid, &op, 1);
  164. }
  165.  
  166. void proces1()
  167. {
  168. wait4pids();
  169.  
  170. char buf[BUFSIZE];
  171.  
  172. while (fgets(buf, sizeof(buf), stdin) > 0)
  173. {
  174. while (stan == CZEKAJ)
  175. pause();
  176.  
  177. sem_down(sem12, ZAPIS);
  178. // opuszczamy semafor synchronizuj±cy zapis
  179. #ifdef _DEBUG
  180. printf("1: wychodzę zza semafora\n");
  181. #endif
  182. // kopiujemy
  183. strncpy(ptr->buf12, buf, sizeof(ptr->buf12));
  184. // strncpy(dok±d, sk±d, ile_najwięcej)
  185.  
  186. sem_up(sem12, ODCZYT);
  187. // podnosimy semafor synchronizuj±cy odczyt
  188.  
  189. usleep(300000);
  190. }
  191. get_sig(SIGINT);
  192. }
  193.  
  194. void rot13(char *a)
  195. {
  196. for (; *a; *a = (*a - 1 / (~(~(*a) | 32) / 13 * 2 - 11) * 13), a++);
  197. // znalazłem na wiki i ciut przerobiłem :)
  198. }
  199.  
  200. void proces2(void)
  201. {
  202. wait4pids();
  203.  
  204. char buf[BUFSIZE];
  205.  
  206. #ifdef _DEBUG
  207. int c = 1000;
  208. #endif
  209. do
  210. {
  211. sem_down(sem12, ODCZYT);
  212. // opuszczamy semafor synchronizuj±cy odczyt (komunikacja 1->2)
  213. #ifdef _DEBUG
  214. printf("2: wychodzę zza semafora\n");
  215. #endif
  216.  
  217. strncpy(buf, ptr->buf12, sizeof(buf));
  218.  
  219. sem_up(sem12, ZAPIS);
  220. // podnosimy semafor synchronizuj±cy zapis (komunikacja 1->2)
  221.  
  222. rot13(buf);
  223. // wykonujemy proste kodowanie
  224.  
  225. sem_down(sem23, ZAPIS);
  226. // opuszczamy semafor synchronizuj±cy zapis (komunikacja 2->3)
  227.  
  228. strncpy(ptr->buf23, buf, sizeof(ptr->buf23));
  229.  
  230. sem_up(sem23, ODCZYT);
  231. // podnosimy semafor synchronizuj±cy odczyt (komunikacja 2->3)
  232.  
  233. #ifdef _DEBUG
  234. } while (--c);
  235. #else
  236. } while (1);
  237. #endif
  238.  
  239. }
  240.  
  241. void proces3(void)
  242. {
  243. wait4pids();
  244.  
  245. char buf[BUFSIZE];
  246.  
  247. #ifdef _DEBUG
  248. int c = 1000;
  249. #endif
  250. do
  251. {
  252. sem_down(sem23, ODCZYT);
  253. // opuszczamy semafor synchronizuj±cy odczyt (komunikacja 2->3)
  254. #ifdef _DEBUG
  255. printf("3: wychodzę zza semafora\n");
  256. #endif
  257.  
  258. strncpy(buf, ptr->buf23, sizeof(buf));
  259.  
  260. sem_up(sem23, ZAPIS);
  261. // podnosimy semafor synchronizuj±cy zapis (komunikacja 2->3)
  262.  
  263. printf(buf);
  264. #ifdef _DEBUG
  265. } while (--c);
  266. #else
  267. } while (1);
  268. #endif
  269. }
  270.  
  271. int main(int argc, char *argv[])
  272. {
  273. shmid = shmget(IPC_PRIVATE, sizeof(mem), 0644);
  274. ptr = (mem *)shmat(shmid, NULL, 0);
  275. // ptr to wskaĽnik na strukturę mem, gdzie będzie wszystko
  276. // pidy rodzeństwa oraz dwa bufory do transmisji (patrz pocz±tek pliku)
  277. if (! ptr)
  278. {
  279. printf("Bł±d shmat\n");
  280. return 1;
  281. }
  282.  
  283. sem12 = semget(IPC_PRIVATE, 2, 0644);
  284. // po dwa semafory dla każdej transmisji 1->2 i 2->3
  285. sem23 = semget(IPC_PRIVATE, 2, 0644);
  286.  
  287. // semafor o indeksie 0 będzie synchronizował odczyt
  288. // semafor o indeksie 1 będzie synchronizował zapis
  289. semctl(sem12, 0, SETVAL, 0);
  290. // semafor do odczytu przy transmisji 1->2 inicjujemy 0
  291. semctl(sem12, 1, SETVAL, 1);
  292. // semafor do zapisu przy transmisji 1->2 inicjujemy 1
  293. semctl(sem23, 0, SETVAL, 0);
  294. // analogicznie
  295. semctl(sem23, 1, SETVAL, 1);
  296. // analogicznie
  297.  
  298. mkfifo(fnames[1], 0644);
  299. mkfifo(fnames[2], 0644);
  300. mkfifo(fnames[3], 0644);
  301. // po jednej kolejce na proces
  302.  
  303. signal(SIGUSR1, get_sig);
  304. signal(SIGUSR2, get_sig);
  305. signal(SIGINT, get_sig);
  306. signal(SIGCONT, get_sig);
  307. // przejęcie obsługi sygnałów propaguje się na wszystkie dzieci
  308.  
  309. ptr->pid[0] = getpid();
  310.  
  311. stan = INIT;
  312.  
  313. int i, pid[4];
  314. if ((pid[1] = fork()) == 0)
  315. proces1();
  316. else if ((pid[2] = fork()) == 0)
  317. proces2();
  318. else if ((pid[3] = fork()) == 0)
  319. proces3();
  320. else
  321. {
  322. for (i = 1; i <= 3; ptr->pid[i] = pid[i], i++)
  323. if (pid[1] < 0)
  324. return 1;
  325. #ifdef _DEBUG
  326. printf("0: pids: %d, %d, %d, %d\n",
  327. ptr->pid[0], ptr->pid[1], ptr->pid[2], ptr->pid[3]);
  328. #endif
  329.  
  330. /* Rodzic w momencie robienia pierwszego dziecka nie wie jak będ± się
  331. * nazywały kolejne (pid), więc nie może mu tego powiedzieć, ale jako¶ musi
  332. * (żeby dzieci mogły ze sob± rozmawiać musz± wiedzieć jak się nazywaj±).
  333. * Dlatego wszystkie imiona l±duj± we wspólnej pamięci, a każde dziecko
  334. * po urodzeniu się zapada w ¶pi±czkę (pause) i czeka aż urodzone zostan±
  335. * wszystkie inne i nadane im zostan± imiona. Wtedy rodzic zabija wszystkie
  336. * swoje dzieci (kill), ale te nie gin± bo rodzic zarejestrował procedurę
  337. * obsługi sygnałów, która przeniosła się na dzieci. Dzieci się budz±,
  338. * odczytuj± swoje imiona, a rodzic może spokojnie dokończyć żywota.
  339. */
  340. kill(ptr->pid[1], SIGINT);
  341. kill(ptr->pid[2], SIGINT);
  342. kill(ptr->pid[3], SIGINT);
  343.  
  344. }
  345.  
  346. return 0;
  347. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement