
Программирование процессов.pptx
- Количество слайдов: 38
Примеры использования системных функций для работы с процессами
Пример. Вывод информации о текущем процессе Каждый процесс имеет ряд важных данных, получить которые можно следующим образом: #include <sys/types. h> #include <unistd. h> #include <pwd. h> //для функции getpwuid () #include <stdio. h> . . . int uid = getuid (); //получить идентификатор пользователя, от лица которого запущен процесс struct passwd * pwdp = getpwuid (uid); //получить имя пользователя // в поле pw_name структуры s truct pwd if (pwdp == NULL) { printf (stderr, "Bad usernamen"); return 1; } printf ("PID: %dn", getpid ()); //получить и вывести идентификатор процесса PID printf ("PPID: %dn", getppid ()); //получить и вывести идентификатор родительского процесса РPID printf ("UID: %dn", uid); //вывести идентификатор пользователя printf ("Username: %sn", pwdp->pw_name); //вывести имя пользователя . . .
Концепция развилки fork() #include <sys/types. h> #include <unistd. h> #include <stdio. h> . . . pid_t result = fork(); //создать новый процесс if (result == -1) { fprintf (stderr, "Errorn"); return 1; } if (result == 0) printf ("I аm child with PID=%dn", getpid ()); else printf ("I аm parent with PID=%dn", getpid ()); . . .
«Непредсказуемость переключения процессов» Ядро периодически даёт возможность каждому процессу передать свой код процессору на выполнение. Эти переключения производятся настолько быстро, что у пользователя создаётся иллюзия одновременной работы нескольких программ. За переключение процессов отвечают специальные алгоритмы ядра ОС. Считается, что алгоритмы переключения процессов непредсказуемы. Иными словами процессы работают независимо друг от друга. Подобная договорённость позволяет ядру «интеллектуально» распределять системные ресурсы между процессами, повышая производительность системы в целом. В следующем примере в каждом процессе запускаются практически одинаковые циклы, которые инкрементируют счётчики в течение трёх секунд. Какая из программ завершиться первой – сказать заранее не возможно. Если окажется так, что сначала завершится родитель, то оболочка «выкинет» своё приглашение, а потом вывод осуществит потомок.
Пример. «Непредсказуемость переключения процессов» #include <stdio. h> #include <sys/types. h> #include <unistd. h> #include <time. h> #define WORKTIME 3 . . . unsigned long parents = 0; unsigned long children = 0; pid_t result; time_t nowtime = time (NULL); // получение системного времени result = fork (); if (!result) { while (time (NULL) < nowtime+WORKTIME) children++; printf ("children: %ldn", children); } else { while (time (NULL) < nowtime+WORKTIME) parents++; printf ("parents: %ldn", parents); }. . .
Передача управления. Функция execve() #include <stdio. h> #include <unistd. h> //для environ extern char ** environ; //внешняя переменная - массив строк вида ПЕРЕМЕННАЯ=ЗНАЧЕНИЕ. . . //служит для передачи окружения в другой процесс //массив аргументов программы, должен заканчиваться NULL char * my_child_args[] = { "lab 4 ", "-a ", NULL}; //загружаем в процесс другую программу и передаем ей управление execve ("/home/student/lab 4", my_child_args, environ); fprintf (stderr, "Errorn"); //обработка ошибки в том случае, если exec() завершился неудачей. . .
Особенности execve() Выполняющийся внутри процесса код называется образом процесса (process image). Системный вызов execve() заменяет текущий образ процесса на новый, а возврата в исходную программу не происходит. В случае ошибки execve() вернёт -1, а в случае успеха он уже ничего не вернёт – работа исходной программы в рамках текущего процесса должна закончиться. Поэтому можно сделать вывод о том, что возврат из системного вызова в исходную программу произойдёт только в случае ошибки. А значит проверка вида if (execve("/home/student", my_child_args, environ)<0) { /*обработка ошибки*/} будет избыточной. В качестве окружения вновь загруженная программа получит массив environ
Пример. Запуск программы с передачей параметров и окружения Исходная программа. Файл firstprog #include <stdio. h> #include <unistd. h> int main (void) { char * args[] = { «Нee-hee!", "arg 1", "arg 2", NULL }; char * envp[] = { "USER=abrakadabra", "HOME=/home/abrakadabra", NULL }; printf ("Old PID: %dn", getpid ()); execve (". /newprog", args, envp); fprintf (stderr, "Errorn"); return 0; } Новая программа. Файл newprog #include <stdio. h> #include <unistd. h> extern char ** environ; int main (int argc, char ** argv) { int i; printf ("ENVIRONMENT: n"); for (i = 0; environ[i] != NULL; i++) printf ("environ[%d]=%sn", i, environ[i]); printf ("ARGUMENTS: n"); for (i = 0; i < argc; i++) printf ("argv[%d]=%sn", i, argv[i]); printf ("New PID: %dn", getpid ()); return 0; } Обе программы выполняются в одном и том же процессе. При помощи execve() программе можно передать любое окружение. В элементе argv[0] можно передать всё что угодно; обычно в нём содержится имя запускаемой программы. Если окружение передавать не нужно, в третьем аргументе можно указать NULL.
Запуск программ в разных процессах #include <stdio. h> #include <unistd. h> #include <sys/types. h> extern char ** environ; int main (void) { pid_t result; char * sleep_args[] = {"sleep", "15", NULL}; result = fork (); if (result == -1) { fprintf (stderr, "fork errorn"); return 1; } if (result == 0) //дочерний { execve ("/bin/sleep", sleep_args, environ); // загрузка программы /bin/sleep с аргументом 15 и без окружения fprintf (stderr, "execve errorn"); return 1; } else //родительский { fprintf (stderr, "I'm parent with PID=%dn", getpid()); } return 0; } Родительская программа порождает дочерний процесс и запускает в нём программу /bin/sleep с аргументом 15. В течение этих 15 секунд можно запустить команду ps и убедиться в наличии отдельного процесса. Вывод родителя производится в стандартный поток ошибок. Это искусственный приём, позволяющий немедленно выводить сообщение на экран, не задумываясь о возможных последствиях буферизации стандартного вывода. Конструкция else является лишней. Почему?
Ожидание процесса. Функция wait() #include <stdio. h> #include <wait. h> #include <unistd. h> #include <sys/types. h> int main (int argc, char ** argv) { pid_t status, childpid; int exit_status; if (argc < 2) //проверка: задан ли аргумент (имя каталога) { fprintf (stderr, "Too few argumentsn"); return 1; } status = fork (); if (status == -1) { fprintf (stderr, "Fork errorn"); return 1; } if (status == 0) //дочерний { execlp ("ls", argv[1], NULL); //запуск программы ls с аргументом argv[1] fprintf (stderr, "Exec errorn"); return 1; } childpid = wait (&exit_status); //родительский if (WIFEXITED (exit_status)) printf ("Process with PID=%d has exited with code=%dn", childpid, WEXITSTATUS (exit_status)); return 0; } WIFEXITED() – макрос, который возвращает ненулевое значение, если потомок завершится посредством возврата из функции main() или через вызов exit(). WEXITSTATUS() – макрос, который возвращает код возврата завершившегося процесса; этот макрос вызывается в том случае, если WIFEXITED вернул ненулевое значение. Запустите программу с существующим каталогом и с несуществующим каталогом в качестве параметра
Ожидание процесса. Функция wait() #include <stdio. h> #include <wait. h> #include <unistd. h> #include <sys/types. h> int main (int argc, char ** argv) { pid_t status, childpid; int exit_status; if (argc < 2) //проверка { fprintf (stderr, "Too few argumentsn"); return 1; } status = fork (); if (status == -1) { fprintf (stderr, "Fork errorn"); return 1; } if (status == 0) //дочерний { execlp ("sleep", "30", NULL); fprintf (stderr, "Exec errorn"); return 1; } childpid = wait (&exit_status); //родительский if (WIFEXITED (exit_status)) printf ("Process with PID=%d has exited with code=%dn", childpid, WEXITSTATUS (exit_status)); if (WIFSIGNALED (exit_status)) printf ("Process with PID=%d has exited with signal. %dn", childpid)); return 0; } WIFSIGNALED() – макрос, который возвращает ненулевое значение, если процесс был завершен посредством получения сигнала. Запустите программу и подождите 30 секунд. Снова запустите и за 30 секунд узнайте номер дочернего процесса и «убейте» его с помощью команды kill.
Программирование процессов.pptx