Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Lek_4,5_.doc
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
412.16 Кб
Скачать

5. Ресурси процесу

При виконанні призначених на процес задач часто приходиться запису­вати дані у файл, відправляти їх на принтер або відображати отримані результа­ти на екран. Процесу можуть знадобитися дані, що вводяться користувачем з клавіатури або які містяться у файлі. Окрім того, процеси у якості ресурсу мо­жуть використовувати інші процеси, наприклад, підпрограми. Підпрограми, файли, семафори, мьютекси, клавіатура та екран дисплеїв – все це приклади ресурсів, які може запросити процес. Під ресурсом розуміємо все, що викорис­товує процес в довільний заданий час в якості джерела даних, засобів обробки, обчислень або відображення інформації.

Щоб процес отримав доступ до ресурсів, він спочатку повинен зробити запит, звернувшись з ним до операційної системи. Якщо ресурс вільний, опера­ці­йна система дозволяє процесу його використати. Після використання ресурсу процес звільняє його, щоб він був доступним для інших процесів. Якщо ресурс недоступний, запит відхиляється, і процес повинен почекати його звільнення. Як тільки ресурс стане доступним, процес активується. Такий основний підхід до розподілення ресурсів між процесами. На рис. 3 подано граф розподілу ресу­рсів, за яким можемо зрозуміти, які процеси утримують ресурси, а які їх очіку­ють. Так, процес В робить запит на ресурс 2, який утримується процесом С. П роцес С робить запит на ресурс 3,який утримується процесом D.

Якщо задовольняється відразу декілька запитів на отримання доступу до ресурсу, даний ресурс є використовується спільно, або поділяється (дана ситу­ація також відображена на рис. 3). Процес А поділяє ресурс R1 з процесом D. Ресурси, які поділяються, можуть позволяти паралельний доступ відразу декі­лькох процесів або дозволяти доступ тільки одному процесу на протязі обмеже­ного проміжку часу, після чого аналогічним доступом зможе скористатися ін­ший процес. Прикладом такого типу ресурсів які поділяються може бути проце­сор. Спочатку процесор призначається одному процесу на протязі короткого інтервалу часу, а потім процесор отримує інший процес. Якщо задовольняє­ть­ся тільки один запит на отримання доступу до ресурсу, і це відбувається після того, як ресурс звільнить інший процес, такий ресурс є не використовується спільно, а про процес говорять, що він має монопольний доступ (exclusive ac­c­ess) до ресурсу. В багатопроцесорному середовищі важливо знати, який дос­туп можемо організувати до ресурсу, який поділяється: паралельний або послідов­ний (передаючи естафету почергово від ресурсу до ресурсу). Це дозволить уни­к­нути капканів, які властиві паралелізму.

Одні ресурси можуть змінюватися або модифікуватися процесами, а інші – ні. Поведінка ресурсів які поділяються і можуть бути модифіковані і не модифіковані визначається типом ресурсів.

Граф розподілу ресурсів

Графи розподілу ресурсів – це напрямлені графи, які показують, як роз­поділяються ресурси в системі. Такий граф складається з множини вершин V та множини ребер Е. Множина вершин ділиться на дві категорії:

P = { P1, P2, . . ., Pn }

R = { R1, R2, . . ., Rn }

Множина Р – це множина всіх процесів, R – це множина всіх ресурсів в системі. Ребро, напрямлене від процесу до ресурсу, називаємо ребром запиту, а ребро, напрямлене від ресурсу до процесу, називаємо ребром призначення. Нап­рямлені ребра позначаються наступним чином:

Pi  Rj Ребро запиту: процес Pi запитує екземпляр типу ресурс Rj

Rj  Pi Ребро призначення: екземпляр типу ресурсу Rj виділено процесу Pi

Кожен процес у графі розподілу ресурсів відображене колом, а кожен ресурс – прямокутник. Оскільки може бути багато екземплярів одного типу ре­сурсу, то кожен з них є крапкою в середині прямокутника. Ребро запиту вказує на периметр прямокутника ресурсу, а ребро призначення бере початок з крапки і доходить до кола процесу.

Граф розподілу ресурсів, подано на рис. 3, показує наступне.

Множина P, R і E

P = { Pа, Pb, Pc, Pd }

R = { R1, R2, R3 }

E = { R1  Pа, R1  Pd, Pb  R2, R2  Pc, Pc  R3, R3  R3 }

5.1. Типи ресурсів

Існує три основних типи ресурсів: апаратні, інформаційні та програмні. Апаратні ресурси є фізичними пристроями, підключеними до комп’ютера (на­приклад: процесори, основна пам'ять і всі пристрої вводу-виводу, включаючи принтер, жорсткий диск, накопичувачі на магнітній стрічці, дисковод з zip-ар­хівом, монітори, клавіатура, звукові, мережеві і графічні карти, а також моде­ми). Всі ці пристрої можуть спільно використовувати декілька процесів.

Деякі апаратні ресурси призупиняються (перериваються), щоб дозволи­ти доступ до них різних процесів. Наприклад, призупинення процесора дозво­ляє різним процесам виконуватися почергово. Оперативний запам’ятовуючий пристрій, або ОЗП (RAM), - це ще один приклад ресурсу, який поділяється за­со­бами призупинення. Коли процес не виконується, деякі сторінкові блоки, які він не займає, можуть бути вивантажені на допоміжні запам’ятовуючі пристрої, а на їх місце завантажені дані, які належать іншому процесу. В довільний мо­мент часу весь діапазон пам’яті може бути зайнятим сторінковими блоками ті­льки одного процесу. Прикладом ресурсу який поділяється, але ресурсу, який не призупиняється, це наприклад принтер. При сумісному використанні прин­тера завдання, які посилають на друк процеси, зберігаються в черзі. Кожне зав­дання друкується до закінчення, і тільки потім починається виконання наступ­ного завдання. Принтер не призупиняється ні одним завданням, що чекає, якщо не відміняється біжуче завдання.

Інформаційні ресурси – до них зараховуємо дані (наприклад, об’єкти), системні дані (наприклад, змінні середовища, файли і дескриптори) а також глобально визначені змінні, як семафори і мьютекси, - є ресурсами, які поділя­ю­ться, і які можуть бути модифіковані процесом. Звичайні файли і файли, по­в’язані з фізичними пристроями (наприклад, принтер), можуть відкриватися з врахуванням обмежуючого доступу зі сторони процесів. Іншими словами, про­цеси можуть володіти правом доступу тільки до читання, або тільки для запису, або для читання та запису. Дочірній процес успадковує ресурси батьківського процесу і права доступу до них, існуючі на момент створення процесу-нащадка. Дочірній процес може перемістити файловий вказівник, закрити, модифікувати або перезаписати зміст файлу, відкритого батьком. Доступ до файлів і пам’яті, які використовуються спільно з дозволом запису, повинно бути синхронізовано. Для синхронізації доступу до ресурсів даних, що поділяються, можемо викори­стати такі засоби, як семафори і мьютекси.

Бібліотеки, що поділяються можуть бути прикладом програмних ресу­рсів. Бібліотеки, що поділяються є колекцією функцій для процесів. Процеси можуть також спільно використовувати додатки, програми та утиліти. В цьому випадку в пам’яті знаходиться тільки одна копія програмного коду, наприклад, додатку. При цьому повинні існувати окремі копії даних, по одній для кожного користувача (процесу). До незмінного програмного коду (який повторно вико­ристовується - реентерабельний) можуть отримати доступ декілька процесів одночасно.

5.2. POSIX-функції для встановлення обмежень доступу до ресурсів

В бібліотеці POSIX визначені функції, які обмежують можливості про­цесу по використанню визначених ресурсів. Так, операційна система встанов­лює обмеження на можливості процесу по використанню системних ресурсів, а власне:

  • розмір стеку процесу;

  • розмір створюваного файлу і файлу ядра;

  • об’єм часу ЦП, виділеного процесу (розмір кванту часу);

  • об’єм пам’яті, що використовується процесом;

  • кількість дескрипторів відкритих файлів.

Операційна система встановлює жорсткі обмеження на використання ресурсів процесом. Процес може встановити або змінити м’які обмеження ресу­рсів, але це значення не може перейти жорстку межу, встановлену операційною системою. Процес може понизити свою жорстку межу, але його значення не повинне перейти м’якої межі. Операція по зниженню процесом своєї жорсткої межі є незворотною . ЇЇ можуть підвищити тільки процеси, які мають спеціальні привілеї.

Синопсис

# include < sys/resource.h >

int setrlimit (int resource, const struct rlimit *rlp);

int getrlimit (int resource, struct rlimit *rlp);

int getrusage (int who, struct rusage *r_usage);

Функція setrlimit () використовується для встановлення обмежень на ви­користання заданих ресурсів. Дана функція дозволяє встановити як жорстку так і м’яку межі. Параметр resource подає тип ресурсу. Значення типів ресурсів (та їх опис) подано в табл. 4. Жорсткі та м’які межі заданого ресурсу подаються параметром rlp, який вказує на структуру rlimit, яка містить два об’єкти типу rlim_t.

іекгсе rlimit

{

rlim_t rlim_cur;

rlim_t rlim_max;

};

Тип rlim_t – це цілий тип без знаку. Елемент rlim_cur містить значення біжучої, або м’якої межі, а елемент rlim_max – значення максимуму, або жорст­кої межі. Елементам rlim_cur і rlim_max можемо надати довільні значення, а та­кож символьні константи, визначені в оголошенні < sys/resource.h >.

RLIM_INFINITY

Відсутні обмеження

RLIM_SAVED_MAX

Непередбачувана жорстка межа, яка зберігається

RLIM_SAVED_CUR

Непередбачувана м’яка межа, яка зберігається

Як жорстку, так і м’яку межі можемо встановити значенню RLIM_ INFINITY, що говорить – ресурс необмежений.

Таблиця 4.

Значення параметру resource

Визначення ресурсу

Опис

RLIMIT_CORE

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

RLIMIT_CPU

Максимальний об’єм часу ЦП в секундах, який може бути використаний процесом

RLIMIT_DATA

Максимальний розмір розділу даних процесу в байтах

RLIMIT_FSIZE

Максимальний розмір файлу в байтах, який може бути створено процесом

RLIMIT_NOFILE

Збільшене на одиницю максимальне значення, яке система може призначити знову створеному дескриптору файлу

RLIMIT_STACK

Максимальний розмір стеку процесу в байтах

RLIMIT_AS

Максимальний розмір доступної пам’яті процесу в байтах

Функція getrlimit () повертає значення м’якої та жорсткої межу заданого ресурсу в об’єкт rlp. Обидві функції повертають значення 0 при успішному за­вершенні і число -1 в іншому випадку. Приклад встановлення м’якої межі для розміру файлів в байтах подано в лістінгу 3.

 Лістінг 3. Використання функції setrlimit () для встановлення м’якої межі

 для розміру файлу

# include < sys/resource.h >

// . . .

struct rlimit R_limit;

struct rlimit R_limit_values;

// . . .

R_limit.rlim_cur = 2000;

R_limit.rlim_max = RLIM_SAVED_MAX;

setrlimit (RLIMIT_FSIZE, R_limit);

getrlimit (RLIMIT_FSIZE, R_limit_values);

cout << “мяка межа для розміру файлів:”

<< R_limit_values.rlim_cur

<< endl;

// . . .

В лістінгу 3 м’яка межа для розміру встановлюється рівною 2000 байт, а жорстка межа – максимально можливому значенню. Функції setrlimit () переда­ю­ться значення RLIMIT_FSIZE і R_limit, а функції getrlimit () – значення RLIMIT_FSIZE і R_limit_values. Після їх виконання на екран виводиться вста­новлене значення м’якої межі.

Функція getrusage () повертає інформацію про використання ресурсів процесом, що викликає. Вона також повертає інформацію про дочірній процес, завершення якого очікує процес, який викликає. Параметр who може мати нас­тупні значення:

RUSAGE_SELF

RUSAGE_CHILDREN

Якщо параметру who передано значення RUSAGE_SELF, то інформація, яка повертається, біде належати (відноситися) до процесу, що викликає. Якщо ж параметр who містить значення RUSAGE_CHILDREN, то інформація, яка повертається буде належати (відноситися) до нащадка процесу, який викликає. Якщо, процес який викликає, не очікує завершення свого нащадка, інформація, пов’язана з ним, відкидається (не враховується). Інформація, яка повертається передається через параметр r_usage, який вказує на структуру rusage. Дана стру­ктура містить елементи, подані в таблиці 5. При вдалому виконанні функція по­вертає число 0, в іншому випадку – число -1.

Таблиця 5. Елементи структури rusage

Елемент структури

Опис

struct timevai ru_utime

Час, затрачений користувачем

struct timevai ru_sutime

Час, використаний системою

long ru_maxrss

Максимальний розмір, встановлений для резидентної програми

long ru_maxixrss

Розмір пам’яті, яка поділяється

long ru_maxidrss

Розмір області даних, що не поділяються

long ru_maxisrss

Розмір області стеків, що не поділяється

long ru_minflt

Кількість запитів на сторінці

long ru_majflt

Кількість помилок через відсутність сторінок

long ru_nswap

Кількість (перекачек) сторінок

long ru_inblock

Блочні операції по вводу даних

long ru_oublock

блочні операції по виводу даних

long ru_msgsnd

Кількість відправлених повідомлень

long ru_msgrcv

Кількість отриманих повідомлень

long ru_nsignals

Кількість отриманих сигналів

long ru_nvcsw

Кількість передбачених перемикань контексту

long ru_nivcsw

Кількість вимушених перемикань контексту

5.3.Асинхронні і синхронні процеси

Асинхронні процеси виконуються незалежно один від одного. Це озна­чає, що процес А буде виконуватися до завершення незалежно до процесу В. Між асинхронними процесами можуть бути прямі родинні (батько-донька) відносини, а можуть і не бути. Якщо процес А створює процес В, вини обидва можуть виконуватися незалежно, але в деякий момент батько повинен отрима­ти статус завершення дочірнього процесу. Якщо між процесами немає прямих родинних відносин, у них може бути загальний предок.

Асинхронні процеси можуть виконуватися послідовно, паралельно або з перекриттям. Ці сценарії подано на рис. 4. В ситуації 1 до кінця виконується процес А, потім процес В і тільки потім виконується до кінця процес С. Це і є послідовне виконання процесів. В ситуації 2 процеси виконуються одночасно. Процеси А і В – активні процеси. Під час виконання процесу А процес В знахо­диться в стані очікування. На протязі деякого інтервалу часу обидва процеси пе­ребувають в режимі очікування. Потім процес В просинається, причому раніше процесу А, а через деякий час просинається і процес А, і тепер обидва процеси виконуються одночасно. Дана ситуація показує, що обидва процеси можуть виконуватися одночасно на певному інтервалі часу. В ситуації 3 вико­н ання процесів А і В перекриваються.

Асинхронні процеси можуть спільно використовувати наступні ресурси: файли і пам'ять. Це може вимагати (або не вимагати) синхронізації або взаємо­дії при розподілі ресурсів. Якщо процеси виконуються послідовно (ситуація 1), то вони не потребують ніякої синхронізації. Наприклад, всі три процеси А, В і С можуть поділяти деяку глобальну змінну. Процес А (перед тим як заверши­ться) записує значення в цю змінну, потім процес В під час свого виконання зчитує дані, що зберігаються в змінній і (перед тим як завершитися) записує до неї своє значення. Потім під час свого виконання процес С зчитує дані з цієї змінної. Але в ситуації 2 і 3 процеси можуть спробувати одночасно модифіку­вати цю змінну, тому тут необхідна синхронізація доступу до змінної.

Ми визначаємо синхронні процеси як процеси, що виконуються почер­гово, коли один процес призупиняє своє виконання до тих пір, доки не завер­ши­ться другий. Наприклад, процес А, батьківський, при виконанні створює про­цес В, дочірній. Процес А призупиняє своє виконання до тих пір, доки не завершиться процес В. Після завершення процесу В його вихідний код розмі­щу­ється в таблицю процесів. Тим самим процес А отримує повідомлення про завершення процесу В. Процес А може продовжити виконання, а потім завер­шиться або завершиться відразу. В цьому випадку виконання процесів А і В є синхронізованим. Сценарій синхронного виконання процесів А і В (для порів­няння) також показано на рис. 4.

5.4. Створення синхронних та асинхронних процесів за допомогою функцій fork (), exec (), system () та posix_spawn ()

Функції fork (), fork-exec і posix_spawn () дозволяють реалізувати асинх­ронні процеси. При використанні функції fork () дублюється образ батьківсько­го процесу. Після створення дочірнього процесу ця функція повертає батьку (через параметр) ідентифікатор (PID) процесу-нащадка і (звичайним шляхом) число 0, що означає – створення процесу пройшло успішно. При цьому батьків­ський процес не призупиняється; обидва процеси продовжують виконуватися незалежно від інструкції, яка знаходиться безпосередньо за викликом функції fork (). При створенні дочірнього процесу засобами fork-exec комбінації його образ ініціюється за допомогою образу нового процесу. Якщо функція exec () виконалася успішно (тобто успішно пройшла ініціалізація), то вона не повертає батьківському процесу ніякого значення. Функції posix_spawn () створюють образ дочірніх процесів та ініціюють їх. Окрім ідентифікатора (PID), що повер­тається через параметр функції posix_spawn () батьківському процесу, звичай­ним шляхом повертається значення, яке є індикатором успішного продовження процесу. Після виконання функції posix_spawn () обидва процеси виконуються одночасно. Функція system () дозволяє створювати синхронні процеси. При цьо­му створюється оболонка, яка виконує системну команду або запускає файл, що виконується. В цьому випадку батьківський процес призупиняється до тих пір, доки не завершиться дочірній процес і функція system () не поверне зна­че­ння.

5.4. Функція wait ()

Асинхронний процес, викликавши функцію wait (), може призупинити виконання до тих пір, доки не завершиться дочірній процес. Після завершення дочірнього процесу батьківський процес, який очікує, зчитує статус завершення свого нащадка, щоб не допустити створення процесу-зомбі. Функція wait () отримує статус завершення з таблиці процесів. Параметр status вказує на об­ласть, яка містить статус завершення дочірнього процесу. Якщо батьківський процес має не один, а декілька дочірніх процесів і деякі з них вже завершилися, функція wait () зчитує з таблиці процесів статус завершення тільки для одного дочірнього процесу. Якщо інформація про статус виявиться доступною ще до виконання функції wait (), ця функція завершиться миттєво. Якщо батьківський процес не має ні одного потомка, ця функція повертає код помилки. Функцію wait () можемо використати також в тому випадку, коли процес, що викликає повинен очікувати до тиж пір, доки не отримає сигнал, щоб потім виконати пе­в­ні дії по його обробці.

Синопсис

# include < sys/wait/h >

pid_t wait (int *status);

pid_t waitpid (pid_t pid, int *status, int oрtions);

Функція waitpid () аналогічна функції wait () за виключенням того, що вона приймає додаткові параметри pid і oрtions. Параметр pid задає множину дочірніх процесів, для яких зчитується параметр завершення. Іншими словами, значення параметра pid визначає, які процеси попадуть в дану множину.

pid > 0

Один дочірній процес

pid = 0

Довільний дочірній процес, груповий ідентифікатор якого співпадає з ідентифікатором процесу, який викликає

pid < -1

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

pid = -1

Довільні дочірніпроцеси

Параметр oрtions визначає, як повинно відбуватися очікування процесу, і може приймати одне із значень наступних констант, визначених в оголошення < sys/wait/h >:

WCONTINUED

Повертає статус завершення довільного дочірнього процесу (заданого параметром pid), про статус не було повідомлено з моменту його зупинки

WUNTRACED

Повертає статус завершення довільного зупиненого дочірнього процесу (заданого параметром pid), про статус не було повідомлено з моменту його зупинки

WNOHANG

Процес, який викликає, не призупиняється, якщо статус завершення дочірнього процесу недосяжний.

Ці константи можуть бути об’єднані за допомогою логічної операції АБО і передані в якості параметра oрtions (наприклад WCONTINUED  WUNTRACED).

Обидві дані функції повертають ідентифікатор (PID) дочірнього проце­су, для якого отримано статус завершення. Якщо значення, які містяться в пара­метрі status, рівне числу 1, це значить, що дочірній процес завершився при нас­тупних умовах:

  • процес повернув значення 0 з функції main ();

  • процес викликав деяку версію функції exit () з аргументом 0;

  • процес був завершений, оскільки завершився останній потік процесу.

В табл. 6 подано макроси, які дозволяють обчислити значення статусу завершення.

Таблиця 6.

Макроси, які дозволяють обчислити значення статусу завершення

Макрос

Опис

WIFEXITED

Приводиться до нульового значення, якщо статус було повернено нормально завершеним дочірнім процесом

WEXITSTATUS

Якщо значення WIFEXITED виявляється ненульовим, то оцінюються молодші 8 біт аргументу status, переданого завершеним дочірнім процесом функції _exit () або exit (), або значення, повернуте функцією main ()

WIFSIGNALED

Приводиться до ненульового значення, якщо статус було повернено від дочірнього процесу, який завершився, оскі­льки йому було відправлено сигнал, але цей сигнал не було перехоплено

WTERMSIG

Якщо значення WIFSIGNALED виявляється не нульовим, то оцінюється номер сигналу, який став причиною завер­ше­ння дочірнього процесу

WIFSTOPPED

Приводиться до ненульового значення, якщо статус було повернено від дочірнього процесу, який в даний момент зупинено

WSTOPSIG

Якщо значення WIFSTOPPED виявляється ненульовим, то оцінюється номер сигналу, який став причиною зупинки дочірнього процесу

WIFCONTINUED

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]