Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
ОС_Шеховцов_1.docx
Скачиваний:
73
Добавлен:
09.11.2019
Размер:
14.73 Mб
Скачать

17.4. Процеси без взаємодії із користувачем

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

17.4.1. Фонові процеси на основі posix

У цьому розділі ознайомимося із особливостями розробки фонових процесів у UNIX-сумісних системах [33, 52]. У них фонові процеси за традицією називають демонами (daemons). До стандартних демонів Linux належать: і nit, що є предком усіх процесів системи; сгоп, що забезпечує запуск програм у певні моменти часу; sendmail, що забезпечує відсилання та отримання електронної пошти тощо.

Сесії та групи процесів

Кожен процес належить до групи процесів, яку позначають ідентифікатором гру­пи процесів (pgid). Ядро може виконувати певні дії над усіма процесами групи (наприклад, відсилати їм усім сигнал). Кожна група може мати лідера групи (у цього процесу ідентифікатор (pid) збігається з ідентифікатором групи). Зви­чайно процес успадковує ідентифікатор групи від свого предка, він може також явно змінити свою групу системним викликом setpgrpO.

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

Кілька груп процесів об'єднують у сесію. Для сесії задають ідентифікатор сесії (sid). Звичайно процеси сесії відповідають набору процесів, які створив користу­вач під час інтерактивного сеансу роботи з системою.

Кожний керуючий термінал пов'язаний із сесією та з однією групою процесів цієї сесії (таку групу називають ще інтерактивною (foreground) групою, усі інші називають фоновими (background), з ними термінали не пов'язані). Протилежне, як і для груп, не завжди вірне - сесія може бути взагалі не пов'язана із керуючим терміналом, у цьому випадку в неї відсутня інтерактивна група.

У кожної сесії є лідер сесії, який відповідає за керування сесією та ізоляцію її від інших; його ідентифікатор збігається з ідентифікатором сесії. Якщо лідер сесії пов'язаний із терміналом, у разі виходу користувача з системи цей процес отри­мує сигнал SIGHUP. Звичайною реакцією на цей сигнал буде завершення роботи процесу-лідера та всіх процесів його сесії.

Коли лідер сесії із терміналом не пов'язаний, сигналу про вихід він не отримає і зможе продовжити виконання після закінчення сеансу роботи. Це особливо важливо для фонових процесів.

Взаємозв'язок між сесіями, групами процесів і керуючими терміналами пока­зана на рис. 17.3.

Створення нової сесії

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

створюють сесію, і поточний процес стає її лідером;

створюють нову групу процесів у рамках сесії, і поточний процес стає її лідером;

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

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

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

Розробка фонового процесу

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

Причини висунення цих вимог наведено нижче.

♦ Демон не може мати керуючого термінала, оскільки не повинен реагувати на пе-

­реривання у разі спроб введення-виведення із використанням такого термінала.

♦ Демон має бути лідером фонової групи процесів і лідером нової сесії, щоб він не міг отримувати сигнали (наприклад, у разі натискання Ctrl+C або виходу із системи).

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

Для того щоб дотриматися всіх вимог, у демоні потрібно виконати певну пос­лідовність дій.

1. Відразу після запуску процес демона має створити нащадка:

if ((pid = fork()) < 0) return -1;

Це потрібно для того, щоб відразу повернутися в командний процесор, вий­шовши з предка на кроці 2. Щоб новий процес гарантовано не міг стати ліде­ром групи процесів, бо він успадковує цю групу від предка - це потрібно пізні­ше для виклику setsidO на кроці 3.

2. Після створення нащадка предок має завершити свою роботу:

if (pid !- 0) { // предок

printf ("демон стартував з pid=£d\n", pid);

exit (0):

  1. Інші кроки відбуваються в нащадку. У ньому потрібно виконати певну послі­довність дій.

♦ Створити нову сесію:

setsidO:

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

♦ Змінити поточний каталог на кореневий каталог системи або конкретний робочий каталог демона:

chdirCV");

Якщо цього не зробити, поточний каталог демона завжди буде тим, з якого він запущений. Тут є ризик, що поточним може виявитися каталог, у який замонтовано файлову систему (у цьому випадку її не можна буде розмонту­вати, поки демон не закінчить роботу).

♦ Можливо, закрити всі відкриті файли (файлові дескриптори):

// закрити наперед визначені дескриптори

for (fd = 0: fd < 3; fd++) close(fd):

♦ Перейти в режим очікування (вже було розглянуто різні способи задания очікування у серверних процесах, найпростіший спосіб — виконати виклик pauseO у циклі):

for (; ;) pause()і

Після запуску демон буде лідером сесії (pid=sid), лідером групи процесів (pid=pgid) і не матиме керуючого термінала, а його предком стане і nit, оскільки безпосередній предок припинив виконання.