Unix процеси

Извор: ВикиЕТФ

Сви процеси осим системских на Unix системима се креирају путем гранања(енг. fork). Форковање процеса се врши тако што се копира процес родитељ а потом ако постоји потреба његов меморијски простор се замењује новим програмом. Једино се системски процеси које ствара кернел и "init" процес који је мајка свих процеса, не стварају на овај начин.

Процес је апстракција програма који се извршава. Од података он садржи меморијски простор, стање, отворене фајлове, PID, PPID,... PID (енг. Proccess ID) је јединствена ознака процеса у систему, користећи ову ознаку шаљемо сигнале процесима, пратимо њихово стање,... Пошто сваки процес има свог родитеља PPID означава родитељски процес.

НАПОМЕНА: Сав програмски код који се налази на овој страни можете скинути са сајта чија се локација налази у одељку везе.

Садржај

ps

Да бисмо прегледали тренутно стање процеса користимо програм "ps". Постоје два скупа опција за рад са "ps" програмом "BSD" и "Unix" тип, ја ћу овде навести само "BSD" подскуп. Најстандарднији начин коришћења програма "ps" са "BSD" скупом опција је следећи:

$ ps aux
USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
1000      6873  0.0  0.0  17156   812 ?        S    17:23   0:00 gnome-pty-helper
1000      6874  0.0  0.3  21112  4068 pts/0    Rs   17:23   0:00 bash
1000      6904  0.0  0.3  21112  4076 pts/1    Ss+  17:23   0:00 bash
1000      7014  0.0  0.0   3904   568 ?        S    17:50   0:00 /bin/sh /usr/lib/openoffice/program/soffice
1000      7029  0.3  7.9 624160 81848 ?        Sl   17:50   0:06 /usr/lib/openoffice/program/soffice.bin
1000      7171  0.0  0.3  21108  4044 pts/2    Ss+  18:17   0:00 bash

Опција "a" селектује све процесе, чак и оне који нису ваши али имају контролни терминал, док опција "x" приказује и процесе без контролног терминала. Опција "u" приказује више података у табели следећег формата:

USER       PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
  1         2    3    4      5     6   7         8     9      10   11
  1. Власник процеса
  2. PID процеса
  3. Проценат процесорског времена које троши процес
  4. Проценат меморије који је заузет од стране процеса
  5. Количина заузетости виртуелног простора
  6. Број заузетих страница у меморији
  7. Контролни терминал
  8. Стање процеса
  9. Време стартовања процеса
  10. Количина искоришћеног процесорског времена
  11. Командна линија

Стат кодови

Примарни стат кодови Опис
D Процес је у стању сна који не може да се прекине (обично је у питању улаз/излаз)
S Процес се налази у стању сна који може да се прекине (чека на догађај)
R Налази се у реду извршавања
T Заустављен од стране сигнала или зато што га прате (енг. trace)
W Страничење (није валидно од кернела 2.6.xx)
X Мртав (не би требало никад да се види)
Z Дефункционални процес, зомби. Процес који је завршен али није ухваћен од стране свог родитеља.
BSD стат кодови Опис
< Виши приоритет
N Нижи приоритет
L Странице су му закључане у меморији
s Власник сесије
l У питању је вишенитни процес
+ Процес се налази у групи која је у првом плану (контрола послова)

kill

Пошто је "kill" уграђена команда у Bash-у користићемо њу за опис.

Да бисмо послали сигнале процесима користимо команду "kill". Ова команда шаље сигнал "TERM" ако нисте експлицитно навели који сигнал се шаље. Синтакса команде је следећа:

$ kill -TERM 123
$ kill -15 123

Овде шаљемо исти сигнал TERM процесу са PID 123. Први пут користимо симболичку ознаку за сигнал, а други пут бројну.

Број Име Подразумевана акција Опис
1 SIGHUP Уништити процес Прекид линије терминала
2 SIGINT Уништити процес Прекидање процеса (Ctrl+C)
3 SIGQUIT Чува слику процеса Прекида процес
9 SIGKILL Уништити процес Убија процес (неухватљив)
15 SIGTERM Уништити процес Софтверски уништавајући сигнал, обично се шаље приликом гашења рачунара свим процесима
17 SIGSTOP Зауставља процес Зауставља (неухватљив)
18 SIGTSTP Зауставља процес Зауставља процес, уобичајено се генерише са тастатуре (Ctrl+z)
19 SIGCONT Игнорисање Наставља процес после заустављања
30 SIGUSR1 Уништити процес Сигнал дефинисан од стране корисника број 1
31 SIGUSR2 Уништити процес Сигнал дефинисан од стране корисника број 2

nice&renice

Сваки процес на UNIX-оликим системима има своју финоћу. То је уствари број који се креће између -20 до 19 а подразумевана вредност је 0. Овај број означава приоритет који утиче на распоређивање процеса од стране менаџера процеса. Финији процеси ће мање да заузимају процесор, док ће они мање фини чешће да га користе. Треба још напоменути да само "root" може да смањује финоћу процеса, док остали корисници могу само да је повећавају.

$ nice -n 10 ls -R

Ова команда покреће команду "ls -R" са повећаном финоћом за 10, што је иначе подразумевана вредност ако је не наведемо.

Програмом "renice" мењамо приоритет програма који су покренути. Овде не додајемо или одузимамо приоритет од постојећег као у "nice" програму већ задајемо апсолутни приоритет. Процесе можемо бирати по њиховом PID-у, власнику и власничкој групи.

$ renice +10 -u korisnik1 korisnik2
$ renice -5  -g neka_grupa1 neka_grupa2
$ renice +10 -p 1234 5678

Прва команда даје апсолутну вредност финоће +10 за процесе који су стартовани од стране корисника "korisnik1" и "korisnik2". Друга команда је пример селекције по групама а трећа по идентификаторима процеса.

fork()

#include <sys/types.h>
#include <unistd.h>
pid_t fork(void);


Функција "fork" ствара нови процес тако што прави идентичну копију процеса родитеља. У родитељском процесу враћа идентификатор детета док у новом процесу враћа вредност нула.

 
 1 #include <sys/types.h>
 2 #include <unistd.h>
 3 #include <stdio.h>
 4 
 5 int main()
 6 {
 7     pid_t pid;
 8     char *message;
 9     int n;
10 
11     printf("fork program se startuje\n");
12     pid = fork();
13     switch(pid) 
14     {
15     case -1:
16         perror("fork je neuspesan");
17         exit(1);
18     case 0:
19         message = "Ovo je dete";
20         n = 5;
21         break;
22     default:
23         message = "Ovo je roditelj";
24         n = 3;
25         break;
26     }
27 
28     for(; n > 0; n--) {
29         puts(message);
30         sleep(1);
31     }
32     exit(0);
33 }

Пошто "fork()" враћа вредност у зависности од процеса ми мењамо понашање програма. Као што видимо у родитељу променљива "n" има вредност 3, док у дете процесу та вредност је 5. То такође илуструје да су адресни простори родитеља и детета одвојени. Ајмо сад да видимо пример извршавања програма.

$ gcc fork1.c -o fork_primer1
$ ./fork_primer1
fork program se startuje
Ovo je dete
Ovo je roditelj
Ovo je dete
Ovo je roditelj
Ovo je dete
Ovo je roditelj
Ovo je dete
$ Ovo je dete

Видимо да иако је родитељ престао са извршавањем дете је наставило да се извршава. Када је родитељ умро процес "init" је прихватио да се брине о дете процесу и покупи његов излаз.


wait()

#include <sys/types.h>
#include <sys/wait.h>

pid_t wait(int *status);


Ако желимо да сачекамо на извршавање изведених процеса користимо функцију "wait()". Она враћа идентификатор сачеканог процеса, а у параметар "status" уписује његову излазну вредност.

37     if(pid) {
38         int   stat_val;
39         pid_t child_pid;
40 
41         child_pid = wait(&stat_val);
42 
43         printf("Dete proces: PID = %d\n", child_pid);
44         if(WIFEXITED(stat_val))
45             printf("Dete proces se zavrsio sa izlasnom vrednoscu %d\n", WEXITSTATUS(stat_val));
46         else
47             printf("Dete proces se zavrsio abnormаlno\n");
48     }

Користимо два макроа за рад са вредношћу статуса, јер изведени процес се не мора завршити регуларно и то је потребно проверити са "WIFEXITED()" макроом. Ако се процес завршио регуларно са макроом "WEXITSTATUS()" вадимо задњих 8 бита од којих се састоји статус из целобројне променљиве "status_val".

signal()

#include <signal.h>

signal(int sig, sig_t func);


Да бисмо хватали сигнале у програмима морамо да наведемо функцију која ће да се извршава уместо подразумеване функције за неки сигнал. У наставку следи пример једног програма који хвата сигнал SIGINT који се иначе генерише са пречицом CTRL-C на тастатури.

 1 #include <signal.h>
 2 #include <stdio.h>
 3 #include <unistd.h>
 4 
 5 void ouch(int sig)
 6 {
 7     printf("OUCH! - Dobio sam signal %d\n", sig);
 8     (void) signal(SIGINT, SIG_DFL);
 9 }
10 
11 
12 int main()
13 {
14     (void) signal(SIGINT, ouch);
15 
16     while(1) {
17         printf("Zdravo svete!\n");
18         sleep(1);
19     }
20 }

Када извршавамо овај програм он ће после сваке секунде да испише поруку. Када му пошаљемо сигнал SIGINT онда ћемо вратити подразумевану акцију за тај сигнал. Тако да ћемо после два послата сигнала SIGINT угасити овај програм.

kill()

#include <sys/types.h>
#include <signal.h>

int kill(pid_t pid, int sig);

Да бисмо слали сигнале процесима на систему користимо системски позив "kill". Наводимо му редом идентификатор процеса и сигнал који желимо да пошаљемо. Следи пример простог програма:

 1 #include  <sys/types.h>
 2 #include  <signal.h>
 3 #include  <stdio.h>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     int signal;
 8     int pid;
 9     int return_val;
10 
11     printf("Unesite PID procesa: ");
12     scanf("%d", &pid);
13 
14     printf("Unesite signal koji zelite da mu posaljete: ");
15     scanf("%d", &signal);
16 
17     return_val = kill(pid, signal);
18     
19     if (return_val == -1) {
20         printf("kill nije bio uspesan.\n");
21     }
22     else {
23         printf("kill je uspesno poslao signal %d procesu %d\n",
24                 signal,
25                 pid);
26     }
27 
28     return 0;
29 }

Везе

Спољашње везе

Личне алатке
Именски простори
Варијанте
Акције
Навигација
Алатке