-
Notifications
You must be signed in to change notification settings - Fork 3
/
m07.html
396 lines (335 loc) · 24.4 KB
/
m07.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
<!DOCTYPE HTML>
<html moznomarginboxes mozdisallowselectionprint>
<head>
<title>DSOP LI0 — Systemy operacyjne — Materiały do zajęć</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<meta name="robots" content="index,follow"/>
<link rel="stylesheet" href="css/reset.css" type="text/css" media="all">
<link rel="stylesheet" href="css/main.css" type="text/css" media="all">
<link href="https://fonts.googleapis.com/css?family=Oxygen:400&subset=latin,latin-ext" rel="stylesheet" type="text/css">
<link href='https://fonts.googleapis.com/css?family=Fira+Sans:400,500,700&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<link href='https://fonts.googleapis.com/css?family=Fira+Mono&subset=latin,latin-ext' rel='stylesheet' type='text/css'>
<!--[if lt IE 9]>
<script type="text/javascript" src="js/html5.js"></script>
<![endif]-->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.2.0/jquery.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML'></script>
<script>
MathJax.Hub.Config({
tex2jax: {
inlineMath: [['$','$'], ['\\(','\\)']],
processEscapes: true,
delayStartupUntil: onload
},
TeX: { equationNumbers: {autoNumber: "AMS"} }
});
</script>
<script type="text/javascript" src="js/js.js"></script>
<link rel="stylesheet" href="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/styles/arduino-light.min.css">
<script src="http://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.4.0/highlight.min.js"></script>
<script>hljs.initHighlightingOnLoad();</script>
</head>
<body>
<div id="wrapper">
<header id="main-header">
<h1>Moduł 7</h1>
<h2>Materiały do zajęć z <i>Systemów operacyjnych</i> prowadzonych na Wydziale Matematyki i Informatyki Uniwersytetu im. Adama Mickiewicza w Poznaniu.</h2>
<h3><a href="index.html" class="button button-grey">« Wróć do spisu materiałów</a></h3>
</header>
<article id="m07">
<h1>Program <code>make</code></h1>
<div class="notice">
<p>W tym paragrafie będziemy korzystać z plików źródłowych dostępnych <a href="files/make.zip">tutaj</a>.</p>
</div>
<p>Choć w przypadku prostych projektów, złożonych z jednego lub dwóch plików źródłowych, ręczne wywoływanie kompilatora nie stanowi problemu, to jednak w przypadku skomplikowanych aplikacji, złożonych już z kilku plików, może to być męczące i wymagające czasowo, szczególnie jeśli kompilacja poszczególnych części zajmuje dużo czasu. Chcielibyśmy bowiem uniknąć sytuacji, w której musimy niepotrzebnie kompilować pewne fragmenty kodu.</p>
<p>Na szczęście program <code>make</code> pozwala nam zautomatyzować proces kompilacji. Poszukuje on w bieżącym katalogu pliku o nazwie <code>makefile</code>, a następnie wykonuje zawarte w nim instrukcje. Jeśli chcemy, aby korzystano z innego pliku z instrukcjami, możemy wywołać program <code>make</code> z opcję <code>-f</code>.</p>
<div class="exercise">
<p>Zapoznaj się z podręcznikiem programu <code>make</code>.</p>
</div>
<p>W ogólności, plik <code>makefile</code> składa się z jednego lub wielu bloków postaci:</p>
<pre><code class="makefile"><!--
-->pliki docelowe: pliki zależne
<!-- -->[tab] polecenie
<!-- --> ...
<!-- --></code></pre>
<p>Jeśli nie stwierdzono inaczej, program <code>make</code> oprze swoje działanie na pierwszym bloku w pliku <code>makefile</code>.</p>
<div class="exercise">
<p>Utwórz w katalogu z projektem plik <code>makefile</code>, o treści:</p>
<pre><code class="makefile"><!--
-->program:
<!-- -->	gcc main.c hello.c silnia.c -o program
<!-- --></code></pre>
<p>a następnie wykonaj polecenie</p>
<pre><code class="no-highlight">$ make</code></pre>
<p>Zapoznaj się z efektami.</p>
</div>
<p>Zawartość pliku docelowego może zależeć od innych plików. W naszym przykładzie, zawartość pliku obiektu <code>main.o</code>, tworzonego w procesie assemblacji, zależy od plików <code>main.c</code> oraz <code>funkcje.h</code>. Jeśli czas modyfikacji któregokolwiek z tych plików będzie nowszy niż czas utworzenia pliku <code>main.o</code>, konieczne jest ponowne wygenerowanie tego ostatniego. Jeśli jednak plik <code>main.o</code> jest nowszy niż wszystkie pliki, od których zależy, nie trzeba go ponownie tworzyć. Dzięki temu można oszczędzić zasoby procesora. Efekt procesu linkowania, równoważny poleceniu</p>
<pre><code class="no-highlight">$ gcc main.o hello.o silnia.o -o program</code></pre>
<p>zależy z kolei od plików obiektów <code>main.o</code>, <code>hello.o</code> oraz <code>silnia.o</code>. Jeśli któryś z nich jest nowszy niż plik <code>program</code>, należy wykonać proces linkowania. W przeciwnym przypadku jest to zbędne. To rozumowanie przedstawia ogólną zasadę działania programu <code>make</code>.</p>
<p>Jeśli w danym bloku pliku <code>makefile</code> zdefiniowane są pliki zależne, muszą one istnieć zanim wykonane zostaną instrukcje z bloku. Może się też zdarzyć, że w wyniku działania innego bloku ich data modyfikacji uległaby zmianie. Dlatego też program <code>make</code> poszukuje w pliku <code>makefile</code> bloków, których wykonanie może mieć wpływ na zawartość plików zależnych i wykonuje te bloki najpierw. Bloki te z kolei mogą zależeć od innych plików, na który wpływ mogą mieć instrukcje w innych blokach itd. Tak oto powstaje drzewo zależności, które jest wpierw konstruowane, a następnie wykonywane od liści do korzenia.</p>
<div class="exercise">
<p>Zmodyfikuj plik <code>makefile</code> z poprzedniego ćwiczenia tak, aby był postaci:</p>
<pre><code class="makefile"><!--
-->program: main.o hello.o silnia.o
<!-- -->	gcc main.o hello.o silnia.o -o program
<!-- -->
<!-- -->main.o: main.c funkcje.h
<!-- -->	gcc -c main.c
<!-- -->
<!-- -->hello.o: hello.c
<!-- -->	gcc -c hello.c
<!-- -->
<!-- -->silnia.o: silnia.c
<!-- -->	gcc -c silnia.c
<!-- -->
<!-- -->clean:
<!-- -->	-rm *.o program
<!-- --></code></pre>
<p>Następnie odwołaj się do instrukcji w odpowiednich blokach pliku <code>makefile</code>, wykonując polecenia:</p>
<pre><code class="no-highlight"><!--
-->$ make hello.o
<!-- -->$ make hello.o
<!-- -->$ make
<!-- -->$ make clean
<!-- --></code></pre>
<p>Zapoznaj się z efektami. Skąd program <code>make</code> wie, że (wraz z wywołaniem drugiego i trzeciego polecenia) nie trzeba ponownie wykonywać instrukcji w bloku generującym plik <code>hello.o</code>? Za co odpowiada symbol łącznika przed poleceniem <code>rm</code> w bloku <code>clean</code>? Dlaczego utworzyliśmy blok <code>clean</code>, mimo że w wyniku poleceń w jego wnętrzu nie jest tworzony żaden plik o takiej nazwie?</p>
</div>
<div class="exercise">
<p>Wykonaj dwukrotnie polecenie</p>
<pre><code class="no-highlight">$ make program</code></pre>
<p>Następnie zmień nieznacznie treść pliku <code>hello.c</code>, by w końcu wykonać ponownie polecenie</p>
<pre><code class="no-highlight">$ make program</code></pre>
<p>Jak zachował się program <code>make</code>? Narysuj drzewo zależności dla bloku <code>program</code> i prześledź sposób <i>myślenia</i> programu, aby wyjaśnić to zachowanie.</p>
</div>
<h1>Funkcje systemowe w języku ANSI C</h1>
<div class="howitworks">
<p>Wraz ze standaryzacją języka C (standard ANSI C) powstała specyfikacja dynamicznej biblioteki standardowej języka C (zwanej <i>ISO C Library</i>), której zadaniem jest udostępnianie programistom pewnych funkcji (takich jak np. <code>printf</code>). Jasne określenie, jakie funkcje mają być dostępne dla programistów, jak mogą być wywoływane i jakie wartości mają zwracać, pozwala tworzyć łatwo przenośne programy. Nie jest jednak zaskoczeniem, że implementacja funkcji z biblioteki standardowej różni się pomiędzy systemami operacyjnymi – korzystają one bowiem z różnych niskopoziomowych funkcji, udostępnianych przez jądro systemu (wywoływanych przez tak zwane <i>system calls</i> lub <i>kernel calls</i>).</p>
<p>Równolegle do standardu ANSI C wprowadzono standard POSIX, który określa funkcje udostępniane przez bibliotekę standardową C (zwaną <i>POSIX C Library</i>) w systemach zgodnych z tym standardem. Tę wersję będziemy nazywać krótko <code>libc</code> i to na niej będziemy opierać się na tych zajęciach.</p>
<p>Biblioteka <code>libc</code> udostępnia generyczną funkcję <code>syscall</code>, zadeklarowaną w nagłówku <code>unisys.h</code>,<sup>[1]</sup> umożliwiającą bezpośrednie odwołania do jądra systemu.<sup>[2]</sup> Udostępnia ona dodatkowo interfejsy do odwołań systemowych, ułatwiające korzystanie z nich. W ramach tych zajęć będziemy korzystać z tych interfejsów, nazywając je dla ułatwienia <i>funkcjami systemowymi</i>.</p>
<div class="exercise">
<p>Dowiedz się, jakie pliki nagłówkowe są związane z biblioteką standardową ISO C, a jakie z biblioteką standardową POSIX C. Odnajdź kody źródłowe nagłówków <code>stdio.h</code>, <code>unisys.h</code> oraz <code>fcntl.h</code> i dowiedz się, jakie funkcje są zadeklarowane w każdym z nich.</p>
</div>
<p class="footnote">[1] Funkcje zdefiniowane w bibliotece standardowej są zadeklarowane w licznych nagłówkach, podzielonych tematycznie.</p>
<p class="footnote">[2] Lista możliwych odwołań dla jądra systemu Linux jest dostępna na przykład na stronie <a href="http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html">http://docs.cs.up.ac.za/programming/asm/derick_tut/syscalls.html</a>, a stałe odpowiadające wartościom liczbowym dla poszczególnych odwołań zadeklarowane są zawsze w nagłówku <code>sys/syscall.h</code>.</p>
</div>
<div class="titbit titbit-star">
<p>W systemach z rodziny Linux oraz FreeBSD biblioteka matematyczna, definiująca funkcje zadeklarowane w nagłówku <code>math.h</code>, jest dostarczana osobno jako <code>libm</code>. W wielu innych systemach funkcje matematyczne są częścią biblioteki standardowej <code>libc</code>.</p>
</div>
<h2>Obsługa plików</h2>
<p>Do obsługi plików możemy wykorzystać funkcje systemowe <code>open</code>, <code>creat</code>, <code>close</code>, <code>read</code>, <code>write</code> oraz <code>lseek</code>. Pierwsze dwie zadeklarowano w nagłówku <code>fcntl.h</code>, pozostałe zaś w nagłówku <code>unistd.h</code>.</p>
<div class="exercise">
<p>Korzystając z poleceń</p>
<pre><code class="no-highlight"><!--
-->$ man 2 read
<!-- -->$ man 2 write
<!-- --></code></pre>
<p>zapoznaj się z konstrukcją funkcji <code>read</code> i <code>write</code>? Jakie przyjmują argumenty? Jakie wartości zwracają?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p>Obie funkcje przyjmują za argumenty, kolejno, numer deskryptora, wskaźnik i rozmiar danych oraz zwracają rozmiar odczytanych/zapisanych danych.</p>
</div>
</div>
<div class="exercise">
<p>Zapoznaj się z poniższym kodem źródłowym:</p>
<pre><code class="c"><!--
-->#include <unistd.h>
<!-- -->
<!-- -->#define BUFSIZ 128
<!-- -->
<!-- -->int main(){
<!-- --> char buf[BUFSIZ];
<!-- --> int n;
<!-- -->
<!-- --> while ((n = read(0, buf, BUFSIZ)) > 0)
<!-- --> write(1, buf, n);
<!-- --> return 0;
<!-- -->}
<!-- --></code></pre>
<p>Co robi ten program? Przeanalizuj jego kod linia po linii. Czy znasz program, który zachowuje się podobnie?</p>
</div>
<div class="exercise">
<p>Zapoznaj się z konstrukcją funkcji <code>creat</code>, <code>open</code>, <code>lseek</code> oraz <code>close</code>. Jakie nagłówki są niezbędne do tego, aby skorzystać z każdej z nich?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p>Funkcje <code>open</code> i <code>creat</code> wymagają nagłówków <code>sys/types.h</code>, <code>sys/stat.h</code> oraz <code>fcntl.h</code>, <code>close</code> nagłówka <code>unistd.h</code>, a <code>lseek</code> nagłówków <code>sys/types.h</code> oraz <code>unistd.h</code>.</p>
</div>
</div>
<p>Funkcja <code>creat</code> zwraca deskryptor utworzonego pliku lub -1, jeśli tworzenie pliku zakończyło się niepowodzeniem. Jako argumenty przyjmuje ścieżkę do pliku i wartość typu <code>mode_t</code>, określającą parametry trybu. Tę ostatnią tworzy się wykorzystując sumę logiczną stałych (flag) zdefiniowanych w pliku nagłówkowym <code>sys/stat.h</code>.</p>
<div class="exercise">
<p>Korzystając z podręcznika funkcji <code>creat</code>, zapoznaj się z flagami trybu (o nazwach rozpoczynających się od <code>S_</code>). Następnie zinterpretuj poniższe wywołania funkcji <code>creat</code>:</p>
<ul>
<li><code>int f = creat("plik.txt", S_IRUSR | S_IRGRP);</code></li>
<li><code>int f = creat("plik.txt", S_IRWXU | S_IRUSR);</code></li>
<li><code>int f = creat("plik.txt", (mode_t) 0644);</code></li>
<li><code>int f = creat("plik.txt", 0644);</code></li>
</ul>
<p>Jak działa operator <code>|</code>? Czy w którymś przypadku flagi się pokrywają (tzn. pominięcie którejś nie wpłynie na wartość sumy logicznej)? Dlaczego trzecie i czwarte wywołanie są równoważne? Czy pominięcie wiodącego zera wpłynie na interpretację wartości? Dlaczego?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p>Trzecie i czwarte wywołania są równoważne, bo rzutowanie typu i tak się odbywa. Wiodące zero jest niezbędne, bowiem wskazuje wyraźnie na to, że liczba jest zapisana w postaci ósemkowej, a nie dziesiętnej.</p>
</div>
</div>
<div class="exercise">
<p>Określ, jak zostanie zinterpretowany ostatni argument wywołania funkcji <code>creat</code>, jeśli napiszemy</p>
<pre><code class="c">int f = creat("plik.txt", 420);</code></pre>
<p>Dlaczego?</p>
</div>
<div class="exercise">
<p>Czy wartość maski uprawnień, określonej za pomocą polecenia <code>umask</code>, ma wpływ na uprawnienia do tworzonych plików?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p>Tak, uprawnienia określone jako argument są filtrowane przez dopełnienie maski.</p>
</div>
</div>
<p>Funkcja <code>open</code> zwraca deskryptor otwartego pliku lub -1, jeśli pliku nie udało się otworzyć. Jako argumenty przyjmuje ścieżkę do pliku, flagi związane z obsługą pliku i (opcjonalnie) argument związany z trybem dostępu do pliku. Podobnie jak w przypadku trybu, flagi związane z obsługą pliku konstruuje się jako sumę logiczną stałych (flag) zdefiniowanych w pliku nagłówkowym <code>fcntl.h</code>.</p>
<div class="exercise">
<p>Korzystając z podręcznika funkcji <code>open</code>, zapoznaj się z następującymi flagami (o nazwach rozpoczynających się od <code>O_</code>), związanymi z obsługą pliku:</p>
<ul>
<li><code>O_CREAT</code>,</li>
<li><code>O_APPEND</code>,</li>
<li><code>O_RDONLY</code>,</li>
<li><code>O_RDWR</code>,</li>
<li><code>O_WRONLY</code>.</li>
</ul>
<p>Następnie zinterpretuj poniższe wywołania funkcji <code>open</code>:</p>
<ul>
<li><code>int f = open("plik.txt", O_RDWR);</code></li>
<li><code>int f = open("plik.txt", O_WRONLY | O_APPEND);</code></li>
<li><code>int f = open("plik.txt", O_RDWR | O_CREAT, S_IRUSR | S_IRGRP);</code></li>
<li><code>int f = open("plik.txt", O_RDONLY | O_CREAT, 0644);</code></li>
</ul>
<p>Kiedy wartość trzeciego argumentu jest brana pod uwagę?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p>Trzeci argument jest brany pod uwagę w chwili tworzenia pliku, to znaczy wtedy, gdy przekazana jako drugi argument wartość wskazuje na wykorzystanie flagi <code>O_CREAT</code>.</p>
</div>
</div>
<div class="exercise">
<p>Utwórz plik o nazwie <code>plik.txt</code> i zawartości równej <code>xxxxxxxxxx</code> (10 razy <code>x</code>). Następnie skompiluj i uruchom następujący program:</p>
<pre><code class="c"><!--
-->#include <sys/types.h>
<!-- -->#include <sys/stat.h>
<!-- -->#include <fcntl.h>
<!-- -->#include <unistd.h>
<!-- -->
<!-- -->#define BUFSIZ 5
<!-- -->
<!-- -->int main(){
<!-- --> char t[BUFSIZ];
<!-- --> int f = open("plik.txt", O_RDWR);
<!-- --> read(f, t, BUFSIZ);
<!-- --> write(f, "X", 1);
<!-- --> return 0;
<!-- -->}
<!-- --></code></pre>
<p>Jak wygląda zawartość pliku <code>plik.txt</code> po jego wykonaniu?</p>
</div>
<p>Do poruszania się wewnątrz pliku służy funkcja <code>lseek</code>. Przyjmuje ona trzy argumenty: deskryptor pliku, dodatnią lub ujemną wartość przesunięcia (w bajtach, typu <code>off_t</code>) oraz jeden z warunków przesunięcia – <code>SEEK_SET</code> (przesunięcie względem początku pliku), <code>SEEK_CUR</code> (przesunięcie względem bieżącej pozycji w pliku) lub <code>SEEK_END</code> (przesunięcie względem końca pliku).</p>
<div class="exercise exercise-star">
<p>Dowiedz się, jak na działanie funkcji <code>lseek</code> wpływają warunki przesunięcia <code>SEEK_DATA</code> oraz <code>SEEK_HOLE</code>.</p>
</div>
<p>Ostatnią z prezentowanych funkcji jest <code>close</code>. Przyjmuje ona jeden argument – deskryptor pliku, który chcemy zamknąć. Jeśli operacja zakończy się powodzeniem, zwracana jest wartość 0.</p>
<div class="howitworks">
<p>System operacyjny dba o to, aby programy nie nadwyrężały komunikacji z plikami. Dlatego też liczba kanałów komunikacji z plikami, z których może jednocześnie korzystać program jest ograniczona. To dobry powód, aby zamykać pliki, z których nie będzie się już korzystać.</p>
</div>
<div class="exercise">
<p>Zapoznaj się z zawartością pliku źródłowego <code>cp.c</code>, dostępnego <a href="files/cp.c">tutaj</a>. Przeanalizuj, w jaki sposób wykorzystane są w nim funkcje systemowe, skompiluj go, a następnie wypróbuj. Jak działa funkcja <code>perror</code>?</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<p><i>The perror() function produces a message on standard error describing
the last error encountered during a call to a system or library
function.</i></p>
</div>
</div>
<div class="exercise">
<p>Napisz program, który wypisuje na ekranie zawartość plików, których nazwy wskazano jako argumenty. Jeśli odczytanie pliku nie jest możliwe, należy wyświetlić odpowiedni błąd.</p>
<p><a href="#" class="button button-blue" rel="answer">Zobacz odpowiedź</a></p>
<div class="answer">
<pre><code class="c"><!--
-->#include <sys/types.h>
<!-- -->#include <sys/stat.h>
<!-- -->#include <fcntl.h>
<!-- -->#include <unistd.h>
<!-- -->#include <errno.h>
<!-- -->
<!-- -->#define BUFSIZ 128
<!-- -->
<!-- -->int main(int argc, char *argv[]){
<!-- --> char buf[BUFSIZ];
<!-- --> int f,i,n;
<!-- -->
<!-- --> for(i=1; i<argc; i++){
<!-- --> if((f = open(argv[i], O_RDONLY)) > 0){
<!-- --> while ((n = read(f, buf, BUFSIZ)) > 0)
<!-- --> write(1, buf, n);
<!-- --> close(f);
<!-- --> } else {
<!-- --> perror(argv[i]);
<!-- --> }
<!-- --> }
<!-- --> return 0;
<!-- -->}
<!-- --></code></pre>
</div>
</div>
<h2>Struktura procesów</h2>
<p>Z wcześniejszych zajęć pamiętamy, że jedną z charakterystycznych cech systemów uniksopodobnych jest hierarchiczna struktura procesów. Fakt, że procesy tworzą strukturę drzewa sprawia, że każdy z nich nie tylko identyfikuje się jednoznacznie wartością PID, ale także (z wyjątkiem procesu <code>init</code>) ma dokładnie jednego rodzica.</p>
<p>W nagłówku <code>unistd.h</code> zadeklarowane są funkcje <code>getpid</code> oraz <code>getppid</code>, obie typu <code>pid_t</code> zdefiniowanego w nagłówku <code>sys/types.h</code>. Zwracają one, odpowiednio, identyfikator bieżącego procesu i jego rodzica.</p>
<div class="exercise">
<p>Przeanalizuj następujący kod źródłowy:</p>
<pre><code class="c"><!--
-->#include <sys/types.h>
<!-- -->#include <unistd.h>
<!-- -->#include <stdio.h>
<!-- -->
<!-- -->int main(){
<!-- --> printf("PID: %d, PPID: %d\n", getpid(), getppid());
<!-- --> return 0;
<!-- -->}
<!-- --></code></pre>
<p>Co robi ten program? Sprawdź, jak zmieni się efekt jego działania z każdym kolejnym jego uruchomieniem. Jaki proces jest związany z wartością zwracaną przez funkcję <code>getppid</code>?</p>
</div>
<p>Do duplikowania procesu służy funkcja <code>fork</code> zadeklarowana w nagłówku <code>unistd.h</code>. Tworzy ona dokładną kopię procesu (wraz ze wszystkimi zmiennymi, zarówno lokalnymi jak i globalnymi), umieszcza go w hierarchii procesów w pozycji dziecka procesu wywołującego, a następnie w obu instancjach zwraca wartość: w procesie macierzystym PID nowego procesu-dziecka, a w utworzonym procesie wartość zero. Jeśli proces duplikacji zakończy się niepowodzeniem, funkcja <code>fork</code> zwróci wartość ujemną.</p>
<div class="exercise">
<p>Przeanalizuj następujący kod źródłowy:</p>
<pre><code class="c"><!--
-->#include <sys/types.h>
<!-- -->#include <unistd.h>
<!-- -->#include <stdio.h>
<!-- -->
<!-- -->int main(){
<!-- --> int pid;
<!-- -->
<!-- --> if((pid = fork()) >= 0){
<!-- --> if(pid == 0){
<!-- --> printf("Dziecko - PPID: %d\n, PID: %d",
<!-- --> getppid(), getpid());
<!-- --> } else {
<!-- --> printf("Rodzic - PPID: %d, PID: %d, CPID: %d\n",
<!-- --> getppid(), getpid(), pid);
<!-- --> }
<!-- --> } else {
<!-- --> perror("fork");
<!-- --> }
<!-- -->
<!-- --> return 0;
<!-- -->}
<!-- --></code></pre>
<p>Co robi ten program? Przetestuj jego działanie.</p>
</div>
<div class="exercise">
<p>Korzystając z zasobów internetu, dowiedz się, jakie mogą być praktyczne zastosowania funkcji <code>fork</code>.<sup>[1]</sup></p>
<p class="footnote">Jeśli jesteś leniwy, wejdź po prostu na stronę <a href="http://stackoverflow.com/questions/985051/what-is-the-purpose-of-fork">http://stackoverflow.com/questions/985051/what-is-the-purpose-of-fork</a>.</p>
</div>
<div class="exercise exercise-star-star">
<p>Co by się stało, gdyby proces rodzica zakończył się przed procesem dziecka? Czy wówczas proces potomny zostałby automatycznie unicestwiony? Jeśli nie, to jaki byłby wówczas identyfikator jego rodzica? Dowiedz się, czym jest (w rozumieniu procesów) sierota i jak tworzy się procesy demonów.</p>
</div>
</article>
<footer id="main-footer">
<p><a href="http://creativecommons.org/licenses/by-nc-sa/4.0/" target="_blank"><img src="img/cc-by-nc-sa.png" /></a></p>
<p>© 2016–2018 Bartłomiej Przybylski. Wszystkie materiały zebrane na tej stronie udostępniane są na licencji Creative Commons Uznanie autorstwa-Użycie niekomercyjne-Na tych samych warunkach 4.0 Międzynarodowe.</p>
</footer>
</div>
</body>
</html>