Процессы и потоки. Общие определения, основные атрибуты, способы создания и завершения процессов

Понятие и характеристика процесса как адресного пространства потоков управления в системном ресурсе. Особенности нормального и аварийного завершение процесса. Опрос и изменение атрибутов процессов, утилита ps. Создание и приоритет процессов, утилит kill.

Рубрика Программирование, компьютеры и кибернетика
Вид лабораторная работа
Язык русский
Дата добавления 27.11.2013
Размер файла 36,2 K

Отправить свою хорошую работу в базу знаний просто. Используйте форму, расположенную ниже

Студенты, аспиранты, молодые ученые, использующие базу знаний в своей учебе и работе, будут вам очень благодарны.

Размещено на http://www.allbest.ru/

2

Процессы и потоки. Общие определения, основные атрибуты, способы создания и завершения процессов

Содержание занятия

1.Теоретическая часть

1.1 Процессы и потоки - основные понятия

1.1.11 Основные понятия

1.1.12 Опрос и изменение атрибутов процессов. Утилита ps

1.1.13 Создание и завершение процессов

1.1.14 Утилита kill

поток процесс системный ресурс утилит

Цель работы: знакомство с процессами и потоками и средствами работы с ними.

1. Теоретическая часть

1.1 Процессы и потоки - основные понятия

1.1.11 Основные понятия

Напомним данное в стандарте POSIX-2001 определение процесса.

Процесс - это адресное пространство вместе с выполняемыми в нем потоками управления, а также системными ресурсами, которые этим потокам требуются.

Каждый процесс обладает целым рядом атрибутов. Важнейшим среди них является идентификатор процесса - положительное целое число, однозначно идентифицирующее процесс в течение времени его жизни.

Процессы могут создаваться и завершаться. Время жизни процесса - это период от его создания до возврата идентификатора операционной системе. После того как процесс создан с помощью функции fork(), он считается активным. До завершения процесса в его рамках существуют по крайней мере один поток управления и адресное пространство.

Процесс может перейти в неактивное состояние, и тогда некоторые из его ресурсов (но не идентификатор) могут быть возвращены системе. Когда по отношению к неактивному процессу выполняют функцию семейства wait(), системе возвращаются остальные ресурсы. Последний из них - идентификатор процесса, и на этом время жизни процесса заканчивается.

Завершение процесса может быть нормальным или аварийным. Нормальное завершение происходит, в частности, при возврате из функции main().

Зомби-процесс - завершившийся процесс, подлежащий ликвидации после того, как код его завершения будет передан ожидающему этого другому процессу. Процесс, создавший данный, называется родительским, в течение времени жизни которого существует идентификатор родительского процесса. По завершении времени жизни указанного процесса родительским становится определяемый реализацией системный процесс.

Группа - совокупность процессов, допускающая согласованную доставку сигналов. У каждой группы имеется уникальный положительный целочисленный идентификатор, представляющий ее в течение времени ее жизни. В такой роли выступает идентификатор процесса, именуемого лидером группы.

Временем жизни группы процессов называют период от создания группы до момента, когда ее покидает последний процесс (по причине завершения или смены группы).

Задание - это набор процессов, составляющих конвейер, а также порожденных ими процессов, входящих в одну группу.

Под управлением заданиями подразумеваются предоставленные пользователям средства выборочно (при)останавливать и затем продолжать (возобновлять) выполнение процессов. На отдельные задания ссылаются с помощью идентификаторов.

Сеансом называется множество групп процессов, сформированное для целей управления заданиями. Каждая группа принадлежит некоторому сеансу; считается, что все процессы группы принадлежат тому же сеансу. Вновь созданный процесс присоединяется к сеансу своего создателя; в дальнейшем принадлежность сеансу может быть изменена.

Время жизни сеанса представляет собой период от создания сеанса до истечения времени жизни всех групп процессов, принадлежавших сеансу.

Лидер сеанса - процесс, создавший данный сеанс.

Управляющим терминалом называется терминал, ассоциированный с сеансом. У сеанса может быть не более одного управляющего терминала, а тот, в свою очередь, ассоциируется ровно с одним сеансом. Некоторые последовательности символов, вводимые с управляющего терминала, вызывают посылку сигналов всем процессам группы, ассоциированной с данным управляющим терминалом.

Управляющий процесс - это лидер сеанса, установивший соединение с управляющим терминалом. Если в дальнейшем терминал перестанет быть управляющим для сеанса, лидер сеанса утратит статус управляющего процесса.

Задания, группы процессов и процессы подразделяются на приоритетные (переднего плана) и фоновые. Процессы переднего плана, в отличие от фоновых, имеют некоторые привилегии при доступе к управляющему терминалу. В сеансе, установившем соединение с управляющим терминалом, может быть не более одной группы процессов, приоритетной по отношению к данному управляющему терминалу.

С каждым процессом ассоциируется идентификатор создавшего его пользователя. Этот атрибут называется реальным идентификатором пользователя процесса.

В момент создания процесса пользователь входил в некоторую группу, идентификатор которой называется реальным идентификатором группы процесса.

Для определения прав процесса (в том числе прав доступа к файлам) применяются действующие идентификаторы пользователя и группы , которые в общем случае могут отличаться от реальных.

Поведение процесса определяется исполняемой в его рамках программой - последовательностью инструкций для решения определенной задачи. Программы хранятся в файлах. В режим файлов входят биты переустановки действующих идентификаторов пользователя (ПДИП) и группы (ПДИГ). Если эти биты взведены, то при запуске программы на выполнение действующие идентификаторы пользователя и группы процесса могут наследоваться у файла.

Стандартом POSIX-2001 предусмотрены также сохраненные переустановленные действующие идентификаторы пользователя (сохраненные ПДП-идентификаторы) и группы (сохраненные ПДГ-идентификаторы) процесса. Эти атрибуты расширяют возможности, связанные со сменой действующих идентификаторов пользователя и группы процесса.

При определении прав доступа к файлам наравне с действующим идентификатором группы процесса используются идентификаторы дополнительных групп.

С процессом ассоциируются маска режима создания файлов, влияющая на устанавливаемый режим доступа к новым файлам, и ограничение на размер записываемых файлов.

Текущий и корневой каталоги и набор дескрипторов открытых файлов также относятся к числу атрибутов процессов.

Все перечисленные выше атрибуты разделяются существующими в рамках процесса потоками управления. К числу индивидуальных атрибутов относятся идентификатор, приоритет и политика планирования, значение переменной errno, ассоциированные с потоком управления пары ключ/значение, а также системные ресурсы, требующиеся для поддержки потока управления.

Всем потокам управления одного процесса доступны все объекты, адреса которых могут быть определены потоком. В число таких объектов входят статические переменные, полученные от функции malloc() области динамической памяти, унаследованная от системно-зависимых функций прямоадресуемая память, автоматические переменные и т.д.

По отношению к потокам управления вводится понятие безопасных функций, которые можно вызывать параллельно в нескольких потоках без нарушения корректности их функционирования. К числу безопасных принадлежат "чистые" функции, а также функции, обеспечивающие взаимное исключение перед доступом к разделяемым объектам. Если в стандарте явно не оговорено противное, функция считается потоковобезопасной.

Выполняющимся (активным) называется поток управления, обрабатываемый в данный момент процессором. В многопроцессорных конфигурациях может одновременно выполняться несколько потоков.

Поток управления считается готовым к выполнению, если он способен стать активным, но не может этого сделать из-за отсутствия свободного процессора.

Поток управления называют вытесненным, когда его выполнение приостановлено из-за того, что другой поток с более высоким приоритетом уже готов к выполнению.

Процесс (поток управления) считается блокированным, если для продолжения его выполнения должно стать истинным некоторое условие, отличное от доступности процессора.

Список потоков управления - это упорядоченный набор готовых к выполнению равноприоритетных потоков, очередность которых определяется политикой планирования. Множество наборов включает все потоки в системе, готовые к выполнению.

Планированием, согласно стандарту POSIX-2001, называется применение политики изменения списков потоков управления, а также политики выбора процесса или готового к выполнению потока управления для перевода как того, так и другого в число активных.

Под политикой планирования понимается набор правил, используемых для определения порядка выполнения процессов или потоков управления при достижении некоторой цели.

Политика планирования воздействует на порядок процессов (потоков управления) по крайней мере в следующих ситуациях:

· когда активный процесс (поток управления) блокируется или вытесняется;

· когда блокированный процесс (поток управления) становится готовым к выполнению.

Область планирования размещения - это набор процессоров, по отношению к которым в какой-то момент времени планируется поток управления.

Областью планирования конкуренции называется свойство потока управления, определяющее набор потоков, с которыми он конкурирует за ресурсы (например, за процессор). В стандарте POSIX-2001 предусмотрены две подобные области - PTHREAD_SCOPE_SYSTEM и PTHREAD_SCOPE_PROCESS.

Данные выше определения будут поясняться и раскрываться по мере описания служебных программ и функций, обслуживающих понятие процесса.

1.1.12 Опрос и изменение атрибутов процессов. Утилита ps

Для выдачи информации о процессах служит утилита ps:

ps [-aA] [-defl] [-G список_групп]

[-o формат] ... [-p список_процессов]

[-t список_терминалов]

[-U список_пользователей]

-g список_групп]

[-n список_имен]

[-u список_пользователей]

По умолчанию информация выдается обо всех процессах, имеющих тот же действующий идентификатор и тот же управляющий терминал, что и у текущего пользователя. При этом выводятся идентификатор процесса, имя управляющего терминала, истраченное к данному моменту процессорное время и имя программы (команды), выполняемой в рамках процесса. Например, выдача команды ps может выглядеть так, как показано в следующем примере

PID TTYTIME CMD

1594 ttyS4 00:00:02 sh

1645 ttyS4 00:00:00 sh

1654 ttyS4 00:02:45 rk.20.01

18356 ttyS4 00:00:00 prconecm

18357 ttyS4 00:00:00 sh

18358 ttyS4 00:00:00 ps

Листинг 7.1. Возможный результат использования утилиты ps.

Если нужна более подробная информация о более широком наборе процессов, следует пользоваться опциями. Перечислим наиболее употребительные из них.

-a

Выдать информацию обо всех процессах, ассоциированных с терминалами. Заметим, однако, что, во-первых, при получении информации о процессах контролируются права доступа (например, пользователю будут видны только порожденные им процессы), а во-вторых, по стандарту реализация может не включать в выдаваемый список лидеров сеансов.

-A

Выдать информацию обо всех процессах.

-G список_групп

Выдать информацию о процессах с заданными реальными идентификаторами групп.

-o формат

Выдать информацию о процессах в заданном формате.

-p список_процессов

Выдать информацию о процессах с заданными идентификаторами.

-t список_терминалов

Выдать информацию о процессах, ассоциированных с заданными терминалами. Способ задания терминалов зависит от реализации. Обычно указывается имя специального файла, например, ttyS4, или, если имя начинается с tty, просто S4.

-U список_пользователей

Выдать информацию о процессах с заданными реальными идентификаторами пользователей (они могут указываться и в виде входных имен).

Все перечисленные опции, кроме -o, ведают отбором процессов. Если задан целый ряд подобных опций, выводится информация обо всех специфицированных ими процессах.

Опции -o (их в командной строке может быть несколько) позволяют задать выходной формат информации о процессах. Указываются выводимые поля и, если нужно, отличные от подразумеваемых тексты соответствующих им заголовков, отделяющиеся от имени поля знаком равенства и продолжающиеся до конца аргумента опции -o.

Перечислим имена полей, которые могут указываться в выходном формате, и соответствующие им подразумеваемые заголовки.

ruser (RUSER)

Выдавать реальный идентификатор пользователя процесса (в символьной или числовой форме).

user (USER)

Действующий идентификатор пользователя процесса.

rgroup (RGROUP)

Реальный идентификатор группы процесса.

group (GROUP)

Действующий идентификатор группы процесса.

pid (PID)

Идентификатор процесса.

ppid (PPID)

Идентификатор родительского процесса.

pgid (PGID)

Идентификатор группы процессов.

pcpu (%CPU)

Процент процессорного времени, потребляемый процессом.

vsz (VSZ)

Размер процесса в (виртуальной) памяти (в килобайтных блоках).

nice (NI)

Число, используемое как рекомендация системе при планировании процессов. Меньшие значения соответствуют более приоритетным процессам.

etime (ELAPSED)

Астрономическое время, прошедшее с момента запуска процесса.

time (TIME)

Процессорное время, потребленное процессом.

tty (TT)

Имя управляющего терминала.

comm (COMMAND)

Имя выполняемой команды (argv [0]).

args (COMMAND)

Выполняемая командная строка.

Например, командная строка, показанная далее породит выдачу, фрагмент которой приведен в в следующем примере

ps -A -o ruser,user,pid,ppid,tty=TTY -o

nice,vsz,args

Листинг 7.2. Пример использования утилиты ps.

RUSER USER PID PPID TTY NI VSZ COMMAND

root root 1 0 ? 0 1372 init [5]

root root 4 1 ? 19 0 [ksoftirqd_CPU0]

root root 555 1 ? 0 1428 syslogd -m 0

root root 560 1 ? 0 1364 klogd -x

rpc rpc 580 1 ? 0 1508 portmap

rpcuser rpcuser 608 1 ? 0 1560 rpc.statd

root root 743 1 ? 0 2620 /usr/sbin/sshd

root root 776 1 ? 0 2200 xinetd -stayalive

-reuse -pidfi

root root 805 1 ? 0 1500 rpc.rquotad

root root 810 1 ? 0 1504 rpc.mountd

root root 897 1 ? 0 3236

/usr/libexec/postfix/master

postfix postfix 906 897 ? 0 3384 nqmgr -l -n

qmgr -t fifo -u -c

root root 918 1 ? 0 1400 gpm -t ps/2

-m /dev/mouse

root root 936 1 ? 0 1548 crond

xfs xfs 968 1 ? 0 4432 xfs -droppriv -daemon

nobody nobody 987 1 ? 0 36488 dictd 1.9.7: 0/0

root daemon 1022 1 ? 0 1404 /usr/sbin/atd

root root 1057 1 ? 0 5768 cupsd

root root 1064 1 tty1 0 1344 /sbin/mingetty tty1

root root 1070 1 ttyS2 0 1352 /sbin/agetty -i -L ttyS2 38400

root root 1072 1 ? 0 2300 login -- galat

galat galat 1086 1072 ttyS4 0 2260 -sh

root root 1124 1085 ? 0 16900

/usr/bin/kdm_greet

postfix postfix 1826 897 ? 0 3304 pickup -l

-t fifo -u -c

galat galat 2013 1171 ttyS4 0 1940 /bin/sh -c

ps -A -o user,pid,pp

galat galat 2014 2013 ttyS4 0 2584 ps -A -o

user,pid,ppid,tty=TTY

Листинг 7.3. Фрагмент возможного результата использования утилиты ps.

Для опроса идентификаторов процесса, родительского процесса и группы процессов предусмотрены функции getpid() и getppid() getpgrp() (см. в следующем примере).

#include <unistd.h>

pid_t getpid (void);

#include <unistd.h>

pid_t getppid (void);

#include <unistd.h>

pid_t getpgrp (void);

Листинг 7.4. getpid(), getppid() и getpgrp().

По стандарту эти функции всегда завершаются успешно, поэтому ошибочных кодов возврата не предусмотрено.

Для установки идентификатора группы процессов в целях управления заданиями предназначена функция setpgid() (см. в следующем примере).

#include <unistd.h>

int setpgid (pid_t pid, pid_t pgid);

Листинг 7.5. Описание функции setpgid().

Выполнение функции setpgid() влечет либо присоединение к существующей группе процессов, либо создание новой группы в рамках сеанса, в который входит вызывающий процесс. Процесс может установить идентификатор группы для себя или для порожденного процесса. Нельзя изменить идентификатор группы процессов лидера сеанса.

В случае успешного завершения функции setpgid() (результат при этом равен нулю) идентификатор группы процессов устанавливается равным pgid для заданного аргументом pid процесса. Если значение pid равно нулю, установка производится для вызывающего процесса. А если значение pgid равно нулю, то в качестве идентификатора группы процессов используется идентификатор процесса, заданного аргументом pid.

Для создания сеанса и установки идентификатора группы процессов служит функция setsid() (см. в следующем примере).

#include <unistd.h>

pid_t setsid (void);

Листинг 7.6. Описание функции setsid().

Если вызывающий процесс не является лидером группы, в результате выполнения функции setsid() будет создан новый сеанс, причем вызывающий процесс станет лидером этого сеанса, равно как и лидером новой группы процессов (без управляющего терминала и без других процессов в группе и сеансе).

Программа, показанная в предыдущем примере, служит примером использования (в том числе некорректного) описанных функций. Возможный результат работы этой программы приведен в в следующем примере.

#include <unistd.h>

#include <sys/types.h>

#include <stdio.h>

int main (void) {

pid_t ppid;

pid_t pgid;

/* Отменим буферизацию стандартного вывода */

setbuf (stdout, NULL);

printf ("Атрибуты текущего процесса: pid: %d,

ppid: %d, pgid: %d\n",

getpid (), ppid = getppid (), pgid =

getpgrp ());

/* Выделимся в новую группу */

if (setpgid (0, 0) != 0) {

perror ("setpgid (0, 0)");

}

printf ("Новая группа текущего процесса: %d\n",

getpgrp ());

/* Попробуем создать новый сеанс */

if (setsid () == (pid_t) (-1)) {

perror ("setsid от имени лидера группы");

}

/* Вернемся в прежнюю группу */

if (setpgid (0, pgid) != 0) {

perror ("setpgid (0, pgid)");

}

printf ("Группа текущего процесса после повторной

смены: %d\n", getpgrp ());

/* Повторим попытку создать новый сеанс */

if (setsid () == (pid_t) (-1)) {

perror ("setsid от имени не-лидера группы");

}

printf ("Группа текущего процесса после создания

нового сеанса: %d\n", getpgrp ());

/* Попробуем сменить группу родительского

процесса */

if (setpgid (ppid, 0) != 0) {

perror ("setpgid (ppid, 0)");

}

/* Попробуем установить несуществующий */

/* идентификатор группы процессов */

if (setpgid (0, ppid) != 0) {

perror ("setpgid (0, ppid)");

}

return (0);

}

Листинг 7.7. Пример программы, использующей функции getpid(), getppid(), getpgrp(), setpgid(), setsid().

Атрибуты текущего процесса: pid: 11726, ppid:

11725, pgid: 1153

Новая группа текущего процесса: 11726

setsid от имени лидера группы: Operation not permitted

Группа текущего процесса после повторной смены:

1153

Группа текущего процесса после создания нового

сеанса: 11726

setpgid (ppid, 0): No such process

setpgid (0, ppid): Operation not permitted

Листинг 7.8. Возможный результат работы программы, показанной в листинге 7.7.

Опрос реальных и действующих идентификаторов пользователя и группы вызывающего процесса осуществляется с помощью функций getuid(), geteuid(), getgid(), getegid() (см. в следующем примере ). Как и getpid(), они всегда завершаются успешно.

#include <unistd.h>

uid_t getuid (void);

#include <unistd.h>

uid_t geteuid (void);

#include <unistd.h>

gid_t getgid (void);

#include <unistd.h>

gid_t getegid (void);

Листинг 7.9. Описание функций getuid(), geteuid(), getgid(), getegid().

Более сложный интерфейс имеет функция getgroups(), предназначенная для получения идентификаторов дополнительных групп вызывающего процесса (см. в следующем примере). Эти идентификаторы (в их число может входить и действующий идентификатор группы процесса) помещаются в массив grouplist.

#include <unistd.h>

int getgroups (int gidsetsize,

gid_t grouplist []);

Листинг 7.10. Описание функции getgroups().

Аргумент gidsetsize задает число элементов в массиве grouplist, а реальное количество записанных идентификаторов групп возвращается в виде результата функции. Если в качестве значения gidsetsize задать нуль, getgroups() выдаст количество дополнительных групп, не модифицируя массив grouplist.

Переустановить действующий идентификатор пользователя вызывающего процесса позволяют функции setuid() и seteuid() (см. в следующем примере). Операция разрешена, если реальный или сохраненный ПДП-идентификатор пользователя совпадает со значением аргумента uid. Помимо этого, обладающие соответствующими привилегиями процессы с помощью функции setuid() могут установить по значению uid все три идентификатора пользователя процесса - реальный, действующий и сохраненный.

#include <unistd.h>

int setuid (uid_t uid);

#include <unistd.h>

int seteuid (uid_t uid);

Листинг 7.11. Описание функций setuid() и seteuid().

Для непривилегированных процессов по соображениям мобильности рекомендуется использование функции seteuid().

Аналогичные функции для переустановки идентификаторов группы процесса показаны в в следующем примере.

#include <unistd.h>

int setgid (gid_t gid);

#include <unistd.h>

int setegid (gid_t gid);

Листинг 7.12. Описание функций setgid() и setegid().

Отметим, что функция для изменения списка дополнительных групп setgroups() относится к числу привилегированных и, следовательно, остается за рамками стандарта POSIX.

Проиллюстрируем использование описанных функций с помощью программы, показанной в следующем примере .

#include <unistd.h>

#include <sys/types.h>

#include <stdio.h>

#include <stdlib.h>

int main (void) {

uid_t uid;

int nsupgroups;

gid_t *supgroupslist;

int i;

/* Отменим буферизацию стандартного вывода */

setbuf (stdout, NULL);

printf ("Идентификаторы пользователя текущего

процесса:\n" " реальный: %d, действующий:

%d\n", uid = getuid (), geteuid ());

printf ("Идентификаторы группы текущего

процесса:\n" " реальный: %d, действующий:

%d\n", getgid (), getegid ());

printf ("Количество дополнительных групп

текущего процесса: %d\n",

nsupgroups = getgroups (0, supgroupslist));

if (nsupgroups > 0) {

if ((supgroupslist = (gid_t *) malloc

(nsupgroups * sizeof (gid_t))) == NULL) {

perror ("MALLOC");

} else if (getgroups (nsupgroups,

supgroupslist) == (-1)) {

perror ("GETGROUPS");

} else {

/* Выдадим идентификаторы дополнительных */

/* групп процесса */

printf ("Идентификаторы дополнительных групп

текущего процесса:\n");

for (i = 0; i < nsupgroups; i++) {

printf (" %d", supgroupslist [i]);

}

printf ("\n");

}

}

/* Попробуем переустановить идентификатор */

/* пользователя процесса */

if (setuid ((uid_t) 1) != 0) {

perror ("setuid (1)");

}

printf ("Идентификаторы пользователя текущего

процесса после первой смены:\n"

" реальный: %d, действующий: %d\n",

getuid (), geteuid ());

/* Попробуем вернуть прежний идентификатор */

/* пользователя процесса */

if (setuid (uid) != 0) {

perror ("setuid (uid)");

}

printf ("Идентификаторы пользователя текущего

процесса после второй смены:\n"

" реальный: %d, действующий: %d\n",

getuid (), geteuid ());

/* Попробуем сменить действующий идентификатор */

/* с помощью функции seteuid() */

if (seteuid ((uid_t) 1) != 0) {

perror ("seteuid (1)");

}

printf ("Идентификаторы пользователя текущего

процесса после третьей смены:\n"

" реальный: %d, действующий: %d\n",

getuid (), geteuid ());

return (0);

}

Листинг 7.13. Пример использования функций опроса и изменения идентификаторов пользователя процесса.

Если эту программу запустить от имени обычного пользователя, результат может выглядеть так, как показано в в следующем примере.

Идентификаторы пользователя текущего процесса:

реальный: 108, действующий: 108

Идентификаторы группы текущего процесса:

реальный: 3, действующий: 3

Количество дополнительных групп текущего процесса: 1

Идентификаторы дополнительных групп текущего процесса: 3

setuid (1): Operation not permitted

Идентификаторы пользователя текущего процесса после первой смены:

реальный: 108, действующий: 108

Идентификаторы пользователя текущего процесса после второй смены:

реальный: 108, действующий: 108

seteuid (1): Operation not permitted

Идентификаторы пользователя текущего процесса после третьей смены:

реальный: 108, действующий: 108

Листинг 7.14. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени обычного пользователя.

После запуска той же программы от имени суперпользователя может получиться результат, показанный в в следующем примере.

Идентификаторы пользователя текущего процесса:

реальный: 0, действующий: 0

Идентификаторы группы текущего процесса:

реальный: 0, действующий: 0

Количество дополнительных групп текущего процесса: 7

Идентификаторы дополнительных групп текущего процесса:

0 1 2 3 4 6 10

Идентификаторы пользователя текущего процесса после первой смены:

реальный: 1, действующий: 1

setuid (uid): Operation not permitted

Идентификаторы пользователя текущего процесса после второй смены:

реальный: 1, действующий: 1

Идентификаторы пользователя текущего процесса после третьей смены:

реальный: 1, действующий: 1

Листинг 7.15. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени суперпользователя.

Утерять статус суперпользователя легко, а вернуть трудно...

Наконец, сделаем владельцем выполнимого файла рассматриваемой программы пользователя с идентификатором 1, то же проделаем с владеющей группой, взведем в режиме этого файла биты ПДИП и ПДИГ(на ОС Linux можно воспользоваться командой chmod ug+s) и вновь запустим его от имени обычного пользователя (см. в следующем примере).

Идентификаторы пользователя текущего процесса:

реальный: 108, действующий: 1

Идентификаторы группы текущего процесса:

реальный: 3, действующий: 1

Количество дополнительных групп текущего процесса: 1

Идентификаторы дополнительных групп текущего процесса:

3

Идентификаторы пользователя текущего процесса после первой смены:

реальный: 108, действующий: 1

Идентификаторы пользователя текущего процесса после второй смены:

реальный: 108, действующий: 108

Идентификаторы пользователя текущего процесса после третьей смены:

реальный: 108, действующий: 1

Листинг 7.16. Возможный результат работы программы, показанной в листинге 7.13 и запущенной от имени обычного пользователя после взведения в режиме выполнимого файла бита ПДИП.

Видно, что сохраненный ПДП-идентификатор помогает непривилегированному процессу переустанавливать действующий идентификатор пользователя.

Отметим, что если функция getgroups() применяется в программе несколько раз, то память под массив supgroupslist лучше отвести по максимуму, воспользовавшись выражением вида nsupgroups = sysconf (_SC_NGROUPS_MAX) + 1;.

Для опроса и/или изменения маски режима создания файлов вызывающего процесса предназначены служебная программа umask:

umask [-S] [маска]

и одноименная функция (см. в следующем примере).

#include <sys/stat.h>>

mode_t umask (mode_t cmask);

Листинг 7.17. Описание функции umask().

Согласно стандарту, в маске могут фигурировать только биты режима доступа к файлам; трактовка прочих бит зависит от реализации.

Для служебной программы umask маска может задаваться и выводиться в символьной и восьмеричной формах. Маска в символьной форме является "позитивной" в том смысле, что заданные в ней биты режима доступа будут сохранены при создании файла. Восьмеричная форма - "негативная", заданные в ней биты будут "вычитаться" (очищаться) из режима доступа, заданного при создании. Синтаксис маски в umask аналогичен утилите chmod. Опция -S предписывает выдавать маску в символьной форме. Функция umask() устанавливает новую ("негативную") маску и возвращает старую. Пример. Последовательность команд, показанная в (7.18), выдаст результат, воспроизведенный в в следующем примере.

umask 0

umask -S

umask -- -x

umask

Листинг 7.18. Пример использования служебной программы umask.

u=rwx,g=rwx,o=rwx 0111

Пример 7.19. Листинг 7.19. Возможный результат использования служебной программы umask.

Обратим внимание на употребление признака конца опций --. Он позволяет задавать аргументы, начинающиеся с минуса. Отметим также, что результаты, выдаваемые umask, могут в дальнейшем использоваться как аргументы данной утилиты (и в символьной, и в восьмеричных формах).

1.1.13 Создание и завершение процессов

Новые процессы создаются при помощи функции fork() (см. в следующем примере).

#include <unistd.h>

pid_t fork (void);

Листинг 7.20. Описание функции fork().

Новый (порожденный) процесс является точной копией процесса, вызвавшего fork() (родительского), за исключением следующих моментов.

1. У порожденного процесса свой идентификатор, равно как и идентификатор родительского процесса.

2. У порожденного процесса собственная копия файловых дескрипторов, ссылающихся на те же описания открытых файлов, что и соответствующие дескрипторы родительского процесса.

3. Порожденный процесс не наследует блокировки файлов, установленные родительским процессом.

4. Порожденный процесс создается с одним потоком управления - копией того, что вызвал fork().

5. Имеются также некоторые тонкости, связанные с обработкой сигналов, на которых мы, однако, останавливаться не будем.

В случае успешного завершения функция fork() возвращает порожденному процессу 0, а родительскому процессу - идентификатор порожденного процесса. После этого оба процесса начинают независимо выполнять инструкции, расположенные за обращением к fork(). При неудаче родительскому процессу возвращается -1, новый процесс не создается.

Поскольку возвращаемые функцией fork() значения различны для обеих копий, родительский и порожденный процессы могут далее выполняться по-разному. Например, процесс-предок переходит в состояние ожидания завершения процесса-потомка либо, если процесс-потомок запущен асинхронно, продолжает выполнение параллельно с ним. Процесс-потомок при помощи функции семейства exec() подменяет программу, которая определяет поведение процесса, и передает ей управление и список аргументов. Напомним, что заголовок функции main() C-программы выглядит в общем случае так, как показано в в следующем примере.

int main (int argc, char *argv []);

Пример 7.21. Заголовок функции main() C-программы.

Значение argc равно количеству аргументов; argv - это массив указателей собственно на аргументы, которые определяются исходя из командной строки, запускающей C-программу. В соответствии с принятым соглашением, значение argc не меньше единицы, а первый элемент массива argv указывает на цепочку символов, содержащую имя выполняемого файла.

Аналогичный смысл имеют аргументы функций семейства exec() (см. в следующем примере).

#include <unistd.h>

extern char **environ;

int execl (const char *path, const char *arg0, ...

/*, (char *) 0 */);

int execv (const char *path, char *const argv []);

int execle (const char *path, const char *arg0,

... /*, (char *) 0, char *const envp [] */);

int execve (const char *path, char *const argv [],

char *const envp []);

int execlp (const char *file, const char *arg0,

... /*, (char *) 0 */);

int execvp (const char *file, char *const argv []);

Пример 7.22. Описание функций семейства exec().

Функции семейства exec() заменяют текущий образ процесса новым (и, следовательно, в случае успешного завершения возврат в вызывающий процесс невозможен). Новый образ создается на основе выполнимого файла, называемого файлом образа процесса.

Переменная environ инициализируется как указатель на массив указателей на составляющие окружение цепочки символов. Массивы argv и environ завершаются пустым указателем. Аргумент path указывает на маршрутное имя файла с новым образом процесса.

Аргумент file имеет аналогичный смысл, однако, если он задан как простое имя, то производится поиск в каталогах, заданных переменной окружения PATH.

Аргументы arg0, ..., являются указателями на цепочки символов, составляющие список аргументов нового образа процесса. Последним в списке располагается пустой указатель, а аргумент arg0 должен указывать на имя файла-образа.

Аргумент envp имеет тот же смысл и назначение, что и переменная environ.

Файловые дескрипторы остаются открытыми в новом образе, если только они не были снабжены флагом FD_CLOEXEC.

Если у файла с новым образом процесса взведен бит ПДИП, действующий идентификатор пользователя процесса переустанавливается равным идентификатору владельца файла (аналогично для группы).

Следующие атрибуты процесса остаются неизменными:

· идентификатор процесса;

· идентификатор родительского процесса;

· идентификатор группы процессов;

· членство в сеансе;

· реальные идентификаторы пользователя и группы процесса;

· идентификаторы дополнительных групп;

· текущий и корневой каталоги;

· маска режима создания файлов;

· атрибуты, связанные с обработкой сигналов.

Родительский процесс реализует ожидание завершения процессов-потомков и получает информацию о его (завершения) статусе с помощью функций семейства wait() (см. в следующем примере). Если информация о статусе завершения была доступна до вызова wait(), родительский процесс не приостанавливается, возврат из wait() происходит немедленно.

#include <sys/wait.h>

pid_t wait (int *stat_loc);

pid_t waitpid (pid_t pid, int *stat_loc,

intoptions);

Пример 7.23. Описание функций семейства wait().

Функция waitpid() эквивалентна wait(), если аргумент pid равен (pid_t) (-1), а аргумент options имеет нулевое значение. Аргумент pid задает набор порожденных процессов, статус завершения которых запрашивается. Значение (pid_t) (-1) представляет произвольный элемент множества порожденных процессов. Если pid > 0>, имеется в виду один процесс с данным идентификатором. Нулевое значение специфицирует любого потомка из той же группы процессов, что и вызывающий. Наконец, при pid < (pid_t) (-1) запрашивается статус завершения любого порожденного процесса из группы, идентификатор которой равен абсолютной величине pid.

Аргумент options задается как побитное ИЛИ следующих флагов, определенных в заголовочном файле <sys/wait.h>.

WNOHANG

Функция waitpid() не приостанавливает выполнение вызывающего потока управления, если запрашиваемый статус не доступен немедленно.

WUNTRACED

Наряду со статусом завершения запрашивать статус остановленных, но еще не опрошенных процессов.

Если запрос статуса порожденного процесса завершился успешно, функции wait() и waitpid() возвращают идентификатор этого процесса и размещают по указателю stat_loc (если он отличен от NULL) значение, которое будет нулевым тогда и только тогда, когда выдан статус порожденного процесса, завершившегося по одной из трех причин:

· произошел возврат из функции main с нулевым результатом;

· порожденный процесс вызвал функцию _exit() или exit() с нулевым аргументом;

· завершились все потоки управления порожденного процесса.

Для анализа целочисленного значения stat_val, на которое указывает аргумент stat_loc, в файле <sys/wait.h> определен набор макросов. Например, значение WIFEXITED (stat_val) будет ненулевым в случае нормального завершения порожденного процесса; при этом WEXITSTATUS (stat_val) возвращает младший байт статуса. Макрос WIFSTOPPED (stat_val) возвращает ненулевое значение, если получен статус останов- ленного процесса.

Процесс может вызвать собственное завершение, обратившись к функциям семейства exit() (см. в следующем примере).

#include <stdlib.h>

void exit (int status);

void _Exit (int status);

#include <unistd.h>

void _exit (int status);

Пример 7.24. Описание функций семейства exit().

Значением аргумента status могут служить константы 0, EXIT_SUCCESS, EXIT_FAILURE или любое другое значение, хотя ожидающему родительскому процессу будет доступен только младший байт статуса (status & 0377).

Функция exit(), в отличие от _Exit() и _exit(), производит аккуратное завершение: выполняет зарегистрированные функции (см. ниже описание функции atexit()), выталкивает буфера, закрывает потоки, удаляет временные файлы и т.д. Функции _Exit() и _exit() эквивалентны. Все функции семейства exit() закрывают файловые дескрипторы, открытые вызывающим процессом.

Если родительский процесс выполняет функции wait() или waitpid(), ему передается младший байт значения status. Если родительский процесс этого не делает, функции семейства exit() переводят вызывающий процесс в состояние зомби.

Если у завершающегося процесса были потомки, родительским для них становится системный процесс, определяемый реализацией.

Функция atexit() (см. в следующем примере) позволяет зарегистрировать функции, которые будут вызываться, если процесс завершается, обращаясь к exit() или возвращаясь из main().

#include <stdlib.h>

int atexit (void (*func) (void));

Пример 7.25. Описание функции atexit().

Реализация должна поддерживать регистрацию по крайней мере тридцати двух функций и вызывать их в обратном порядке.

В в следующем примере приведен пример использования функций порождения и завершения процессов.

#include <unistd.h>

#include <stdlib.h>

#include <stdio.h>

#include <sys/wait.h>

static void atefunc (void) {

/* Перед завершением выдадим информацию о */

/* процессах */

printf ("Ситуация перед завершением

родительского процесса\n");

(void) system ("ps -o pid,ppid,vsz,args");

}

int main (void) {

int pid;

int stat;

/* Отменим буферизацию стандартного вывода */

setbuf (stdout, NULL);

/* Зарегистрируем обработчик завершения процесса */

if (atexit (atefunc) != 0) {

perror ("ATEXIT");

exit (1);

}

/* Создадим новый процесс */

if ((pid = fork ()) < 0) {

perror ("FORK");

exit (2);

} else if (pid == 0) {

/* Порожденный процесс */

/* Выполним служебную программу ps */

printf ("Ситуация с точки зрения порожденного

процесса\n");

(void) execl ("/bin/ps", "ps", "-o",

"pid,ppid,args", (char *) 0);

perror ("EXEC");

exit (3); /* execl() завершился неудачей */

} else {

/* Родительский процесс */

sleep (1);

/* Вероятно, порожденный процесс уже */

/* завершился */

/* Посмотрим на текущую ситуацию */

printf ("Ситуация перед вызовом waitpid() в

родительском процессе\n");

(void) system ("ps -o pid,ppid,vsz,args");

(void) waitpid (pid, &stat, 0);

printf ("Статус завершения порожденного

процесса с идентификатором %d: %d\n", pid, stat);

}

return 0;

}

Пример 7.26. Пример использования функций порождения и завершения процессов.

Результат работы этой программы может выглядеть так, как показано в в следующем примере (выполнимый файл программы имеет имя prog30).

Ситуация с точки зрения порожденного процесса

PID PPID COMMAND

6123 1072 -sh

29568 6123 prog30

29569 29568 ps -o pid,ppid,args

Ситуация перед вызовом waitpid() в родительском

процессе

PID PPID VSZ COMMAND

6123 1072 2260 -sh

29568 6123 1340 prog30

29569 29568 0 [ps <defunct>]

29570 29568 2584 ps -o pid,ppid,vsz,args

Статус завершения порожденного процесса с

идентификатором 29569: 0

Ситуация перед завершением родительского процесса

PID PPID VSZ COMMAND

6123 1072 2260 -sh

29568 6123 1340 prog30

29571 29568 2584 ps -o pid,ppid,vsz,args

Пример 7.27. Возможный результат работы программы, использующей функции порождения и завершения процессов.

Обратим внимание на информацию о зомби-процессе (с пометкой <defunct>), а также на то, что функция, зарегистрированная с помощью atexit(), вызвана в результате возврата из main().

1.1.14 Утилита kill

Для терминирования процессов извне предназначена служебная программа kill, вызванная следующим образом:

kill -s TERM идентификатор_процесса ...

Если это не помогло, можно применить более сильный вариант:

kill -s KILL идентификатор_процесса ...

Разумеется, попытки терминирования процессов подвержены контролю прав доступа.

Размещено на Allbest.ru

...

Подобные документы

  • Основные структуры процессов в операционной системе Unix. Возможные состояния процесса в Unix и способы перехода между ними. Планирование и выполнение процессов. Различия между родительским и дочерним процессом. Ожидание завершения и выполнения процесса.

    курсовая работа [673,0 K], добавлен 24.02.2012

  • Понятие процесса в информатике, изменение его состояния при исполнении. Очереди, связанные с диспетчеризацией процессов (графическое представление). Долговременные и кратковременные планировщики. Адресация, создание и уничтожение процесса (в UNIX).

    презентация [1,6 M], добавлен 24.01.2014

  • События для создания процесса при запуске операционной системы. Распределении времени процессоров между выполняющимися процессами. Программа, реализующая модель обслуживания процессов с абсолютными приоритетами обслуживания и заданным квантом времени.

    контрольная работа [142,4 K], добавлен 09.12.2013

  • Структура ядра операционной системы. Основные компоненты подсистемы управления процессами и памятью. Характеристика системных и прикладных процессов в Unix. Идентификация процесса Linux, его атрибуты и вызовы. Средства межпроцессного взаимодействия.

    лекция [170,1 K], добавлен 29.07.2012

  • Особенности разработки при использовании потоков. Создание, удаление переменных. Свойства, управление потоками. Вызовы для создания мутекс. Причины завершения потока. Методы синхронизации выполнения потоков. Типичная последовательность действий с мутест.

    лекция [160,8 K], добавлен 29.07.2012

  • Общность информационных процессов в живой природе, технике, обществе. Определение понятия "субъект", структура семантического пространства субъекта. Классификация информационных процессов, когнитивные информационные процессы, информация в кибернетике.

    реферат [58,4 K], добавлен 27.03.2010

  • Программные средства и системы для создания, автоматизирования технологических процессов. Разработка технологического процесса в системе "Вертикаль". Создание 3D моделей операционных заготовок в системе "Catia", технологической оснастки в "Solid Works".

    дипломная работа [6,1 M], добавлен 25.06.2012

  • Процессом как экземпляр выполняемой программы, его структура и основные элементы в Windows. Назначение нитей и волокон. Порядок создания и завершения процессов, разработки и уничтожения нитей и волокон. Способы выполнения работы нити, Wait-функции.

    реферат [15,7 K], добавлен 14.07.2009

  • Научные принципы организации процессов производства. Разработка программного обеспечения имитационного моделирования производственных процессов машиностроительного предприятия с помощью построения технологической линии производственного процесса.

    дипломная работа [2,8 M], добавлен 06.03.2013

  • Основные функции и процессы подсистемы управления процессами. Диспетчеризация процессов (потоков). Алгоритмы планирования выполнения потоков. Назначение и разновидности приоритетов в операционных системах. Функции подсистемы управления основной памятью.

    презентация [117,7 K], добавлен 20.12.2013

  • Обзор операционных систем, обеспечивающих взаимную синхронизацию процессов и потоков. Понятие критической секции и критических данных, описание приема взаимного исключения. Использование блокирующих переменных и семафоров. Объекты-взаимоисключения.

    доклад [26,7 K], добавлен 27.12.2013

  • Создание сложных автоматизированных компьютерных издательских систем и компонентов. Автоматизация проектирования процессов выполнения заказов на примере процесса изготовления каталога. Выбор и использование программных средств для реализации проекта.

    курсовая работа [4,5 M], добавлен 27.03.2012

  • Моделирование регламента Центра сертификации ключей ЗАО "Инфраструктура открытых ключей" с учётом требований безопасности. Основные определения и понятия моделирования процессов. Функции программно-технического комплекса центра. Атрибуты безопасности.

    дипломная работа [563,4 K], добавлен 20.03.2012

  • Понятие процесса и потока, характеристика их свойств и особенности создания. Требования к алгоритмам синхронизации, суть взаимного исключения на примере монитора и семафора. Методика изучения элективного курса "Процессы в операционной системе Windows".

    дипломная работа [1,7 M], добавлен 03.06.2012

  • Количественная, сторона процессов обслуживания потоков сообщений в системах распределения информации. Основные задачи теории телетрафика и сведения о методах решения задач. Принципы классификации потоков вызовов. Просеивание потоков и потоки Эрланга.

    реферат [124,6 K], добавлен 18.02.2012

  • Рассмотрение способов просмотра состояния процессов через диспетер задач в операционной системе Windows: определение взаимосвязи процессов и потоков, времени работы системы в пользовательском режиме. Ознакомление со сведениями о файлах драйверов.

    лабораторная работа [3,1 M], добавлен 07.04.2010

  • Определение критериев для сравнения методик управления требованиями. Особенности создания заказного программного обеспечения. Разработка показателей эффективности процессов управления требованиями. Оценка текущих процессов реализации проектов компании.

    дипломная работа [1,7 M], добавлен 31.10.2016

  • Платформа для выполнения программ, созданных на графическом языке программирования "G" фирмы National Instruments. Дискретизация непрерывных процессов. Восстановление непрерывного процесса по дискретным отсчетам. Построение ВП "Дискретизация процессов".

    реферат [278,7 K], добавлен 19.03.2011

  • Взаимодействие процессов и потоков в операционной системе, основные алгоритмы и механизмы синхронизации. Разработка школьного курса по изучению процессов в операционной системе Windows для 10-11 классов. Методические рекомендации по курсу для учителей.

    дипломная работа [3,2 M], добавлен 29.06.2012

  • Начало любого диалогового проектирования технологических процессов - открытие базы конкретных технологических процессов. Основные операции для совершения технологических процессов. Приемы работы по просмотру и редактированию документов в Microsoft Word.

    контрольная работа [3,7 M], добавлен 30.12.2010

Работы в архивах красиво оформлены согласно требованиям ВУЗов и содержат рисунки, диаграммы, формулы и т.д.
PPT, PPTX и PDF-файлы представлены только в архивах.
Рекомендуем скачать работу.