Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Системні виклики для роботи із процесамиСодержание книги
Поиск на нашем сайте
Розглянемо системні виклики, що використовуються при роботі із процесами в ОС Linux і описані в бібліотеці <fcntl.h>. Системний виклик fork створює новий процес, копіюючи викликаючий процес; виклик exit завершує виконання процесу; wait дає можливість батьківському процесу синхронізувати своє продовження із завершенням породженого процесу, а sleep припиняє на певний час виконання процесу. Системний виклик exec дає процесу можливість запускати на виконання іншу програму. FORK Створення нового процесу: int fork(void); pid = fork(); В ході виконання функції ядро виконують наступну послідовність дій: – відводить місце в таблиці процесів під новий процес; – присвоює породжуваному процесу унікальний код ідентифікації; – робить копію контексту батьківського процесу. Оскільки ті або інші складові процесу, такі як область команд, можуть розділятися іншими процесами, ядро може іноді замість копіювання області в нову фізичну ділянку пам’яті просто збільшити значення лічильника посилань на область; – збільшує значення лічильника числа файлів, пов’язаних із процесом, як у таблиці файлів, так і у таблиці індексів; – повертає батьківському процесу код ідентифікації породженого процесу, а породженому процесу – 0. У результаті виконання функції fork контекст користувача обох процесів збігається у всьому, крім значення, що повертається змінній pid. Якщо процес не може бути породжений, функція повертає негативний код помилки. Процес, що викликає функцію fork, називається батьківським (процес-батько або процес-предок), знову створюваний процес називається породженим (процес-нащадок). Процес-нащадок завжди має більше високий пріоритет, чим процес-предок, тому що пріоритет процесу є найвищим у момент породження і зменшується в міру знаходження в стані виконання. Нульовий процес, що виникає усередині ядра при завантаженні системи, є єдиним процесом, не створюваним за допомогою функції fork. EXIT Завершення виконання процесу: void exit(int status); де status – значення, що повертається функцією батьківському процесу. Процеси можуть викликати функцію exit як у явному, так й у неявному виді (по закінченні виконання програми функція exit викликається автоматично з параметром 0). Також ядро може викликати функцію exit зі своєї ініціативи, якщо процес не прийняв надісланий йому сигнал. У цьому випадку значення параметра status дорівнює номеру сигналу. Виконання виклику exit призводить до “припинення існування” процесу, звільнення ресурсів і ліквідації контексту. WAIT Очікування завершення виконання процесу-нащадка: int wait(int *stat); pid = wait(stat_addr); де pid – значення коду ідентифікації (PID) нащадка, що завершився, stat_addr – адреса змінної цілого типу, у яку буде поміщене значення, що повертається функцією exit. За допомогою цієї функції процес синхронізує продовження свого виконання з моментом завершення нащадка. Ядро веде пошук нащадків процесу, що припинили існування, і у випадку їхньої відсутності повертає помилку. Якщо виявлений нащадок, що припинив існування, ядро передає його код ідентифікації й значення, що повертається через параметр функції exit, процесу, що викликав функцію wait. Таким чином, через параметр функції exit (status) процес, що завершується, може передавати різні значення у закодованому вигляді отримувачу інформації про причину завершення процесу, однак на практиці цей параметр використається за призначенням досить рідко. Якщо процес, що виконує функцію wait, має нащадків, що продовжують існування, він припиняється до одержання очікуваного сигналу. Ядро не відновляє зі своєї ініціативи процес, що призупинився за допомогою функції wait: такий процес може відновитися тільки у випадку одержання сигналу про “загибель нащадка”. SLEEP Призупинка роботи процесу на певний час: void sleep(unsigned seconds); де seconds – кількість секунд, на яке потрібно призупинити роботу процесу. Спочатку ядро підвищує пріоритет роботи процесу так, щоб заблокувати всі переривання, які могли б (шляхом створення конкуренції) перешкодити роботі із чергами припинених процесів, і запам’ятовує старий пріоритет, щоб відновити його, коли виконання процесу буде відновлено. Процес одержує позначку “припиненого”, адреса призупинки та пріоритет запам’ятовуються в таблиці процесів, а процес поміщається у чергу призупинених процесів. У найпростішому випадку (коли призупинка не допускає переривань) процес виконує перемикання контексту і благополучно “засинає”. Коли припинений процес “пробуджується”, ядро починає планувати його запуск. Таким чином, не можна гарантувати, що після закінчення заданого часу припинений процес відразу відновить свою роботу: він може бути вивантажений на час призупинки і тоді потрібно його підкачування в пам’ять; у цей час на виконанні може перебувати процес із більш високим пріоритетом або процес, що не допускає переривань (наприклад, що перебуває в критичному інтервалі) і т.д. Параметр seconds встановлює мінімальний інтервал, протягом якого процес буде призупинений, а реальний час призупинки завжди буде трохи більшим, хоча б за рахунок часу, необхідного для перемикання процесів.
EXEC Запуск програми. Системний виклик exec здійснює кілька бібліотечних функцій – execl, execv, execle та ін. наведемо формат однієї з них: int execv(char *path, char *argv[ ]); res = execv(path, argv); де path – ім’я виконуваного файла, argv – покажчик на масив параметрів, які передаються програмі. Цей масив аналогічний параметру argv командного рядка функції main. Список argv повинен містити мінімум два параметри: перший – ім’я програми, що підлягає виконанню (відображається в argv[0] функції main нової програми), другий – NULL (завершальний список аргументів). Системний виклик exec дає можливість процесу запускати іншу програму, при цьому відповідний цій програмі виконуваний файл буде розташовуватися в просторі пам’яті процесу. Вміст користувацького контексту після виклику функції стає недоступним, за винятком переданих функції параметрів, які переписуються ядром зі старого адресного простору в новий. Виклик exec повертає 0 при успішному завершенні та –1 при аварійному. В останньому випадку керування повертається у про-граму, що викликає. Як приклад використання цього виклику можна розглядати роботу командного інтерпретатора shell: при виконанні команди він спочатку породжує свою копію за допомогою виклику fork, а потім запускає відповідно зазначеній команді програму системним викликом exec. Системні виклики для роботи із сигналами Розглянемо найбільш часто використовувані системні виклики при роботі із сигналами в ОС Linux, описані в бібліотеці <signal.h>.
KILL Посилка всім або деяким процесам будь-якого сигналу: int kill(pid, sig); де sig – номер сигналу, pid – ідентифікатор процесу, що визначає групу родинних процесів, яким буде посланий сигнал: – якщо pid – позитивне ціле число, ядро посилає сигнал процесу з ідентифікатором pid. – якщо значення pid дорівнює 0, сигнал посилається всім процесам, що входять в одну групу із процесом, що викликав функцію kill. – якщо значення pid дорівнює –1, сигнал посилається всім процесам, у яких реальний код ідентифікації користувача збігається з тим, під яким виконується процес, що викликав функцію kill. Якщо процес, що послав сигнал, виконується під кодом ідентифікації суперкористувача, сигнал розсилається всім процесам, крім процесів з ідентифікаторами 0 та 1. – якщо pid – від’ємне ціле число, але не –1, сигнал посилається всім процесам, що входять у групу з номером, рівним абсолютному значенню pid. Виклик kill повертає 0 при успішному завершенні та –1 при аварійному (наприклад, специфікація неіснуючого в ОС Linux сигналу або неіснуючого процесу). У всіх випадках, якщо процес, що послав сигнал, виконується під кодом ідентифікації користувача, що не є суперкористувачем, або якщо коди ідентифікації користувача (реальний і виконуваний) у цього процесу не збігаються з відповідними кодами процесу, що приймає сигнал, kill завершується невдало. Посилка сигналу може супроводжувати виникнення будь-якої події. Сигнали SIGUSR1, SIGUSR2 та SIGKILL можуть бути послані тільки за допомогою системного виклику kill.
SIGNAL Дозволяє процесу самому визначити свою реакцію на одержання того або іншого сигналу: #include <signal.h> int signum; void handler(int); void (*signal(signum, void (*handler)(int)))(int) Після визначення реакції на сигнал signal при одержанні процесом цього сигналу буде автоматично викликатися функція handler(), яка повинна бути описана або оголошена перш, ніж буде здійснений системний виклик signal. При багаторазовій обробці того самого сигналу, процес повинен щораз здійснювати системний виклик signal для встановлення необхідної реакції на даний сигнал. Використання констант SIG_DFL і SIG_IGN дозволяє спростити реалізацію двох найчастіших реакцій процесу на сигнал: – signal(SIGINT,SIG_IGN) – ігнорування сигналу; – signal(SIGINT,SIG_DFL) – відновлення стандартної реакції на сигнал. Аргументом функції-оброблювача є ціле число – номер оброблюваного сигналу. Значення його встановлюється ядром.
PAUSE Припиняє функціонування процесу до одержання ним деякого сигналу: void pause(); Цей системний виклик не має параметрів. Робота процесу відновлюється після одержання ним будь-якого сигналу, крім тих, які ігноруються цим процесом.
ALARM Посилка процесу сигналу побудки SIGALARM: unsigned alarm(unsigned secs); Цим системним викликом процес інформує ядро ОС про те, що ядро повинне послати цьому процесу сигнал побудки через secs секунд. Виклик alarm повертає число секунд, задане при попередньому здійсненні цього системного виклику. Якщо secs дорівнює 0, то специфіковане раніше посилка процесу сигналу SIGALARM буде скасована. Наведена нижче програма в результаті виконання породить три процеси (процес-предок 1 і процеси-нащадки 2 та 3). #include <sys/types.h> #include <fcntl.h> #include <stdio.h void main(void) { int pid2, pid3, st; /* process 1 */ printf(“Process 1, pid = %d:\n”, getpid()); pid2 = fork(); if (pid2 == 0) /* process 2 */ { printf(“Process 2, pid = %d:\n”, getpid()); pid3 = fork(); if (pid3 == 0) /* process 3 */ { printf(“Process 3, pid = %d:\n”, getpid()); sleep(2); printf(“Process 3: end\n”); } /* process 2 */ if (pid3 < 0) printf(“Cann’t create process 3: error %d\n”, pid3); wait(&st); printf(“Process 2: end\n”); } else /* process 1 */ { if (pid2 < 0) printf(“Cann’t create process 2: error %d\n”, pid2); wait(&st); printf(“Process 1: end\n”); } exit(0); } Відповідно до програми спочатку буде створений процес 1 (як нащадок інтерпретатора shell), він повідомить про початок своєї роботи і породить процес 2. Після цього робота процесу 1 призупиниться і почне виконуватися процес 2, як більш пріоритетний. Він також повідомить про початок своєї роботи й породить процес 3. Далі почне виконуватися процес 3, він повідомить про початок роботи і “засне”. Після цього відновить своє виконання або процес 1, або процес 2 залежно від величин пріоритетів і від того, наскільки процесор завантажений іншими процесами. Оскільки жоден із процесів не виконує ніякої роботи, вони, найімовірніше, встигнуть завершиться до поновлення процесу 3, який у цьому випадку завершиться останнім. Приклад синхронізації роботи процесів. Програма в результаті виконання породить три процеси (процес-предок 0 і процеси-нащадки 1 та 2). Процеси 1 та 2 будуть обмінюватися сигналами і видавати відповідні повідомлення на екран, а процес 0 через певну кількість секунд відправить процесам 1 та 2 сигнал завершення і сам припинить своє функціонування. #include <sys/types.h> #include <fcntl.h> #include <stdio.h> #include <signal.h> #include <unistd.h> #define TIMEOUT 10 extern int f1(int), f2(int), f3(int); int pid0, pid1, pid2; void main(void) { setpgrp(); pid0 = getpid(); pid1 = fork(); if (pid1 == 0) /* process 1 */ { signal(SIGUSR1, f1); pid1 = getpid(); pid2 = fork(); if (pid2 < 0) puts(«Fork error»); if (pid2 > 0) for(;;); else /* process 2 */ { signal(SIGUSR2, f2); pid2 = getpid(); kill(pid1,SIGUSR1); for (;;); } } else /* process 0 */ { signal(SIGALRM, f3); alarm(TIMEOUT); pause(); } exit(0); } int f1(int signum) { signal(SIGUSR1, f1); printf(«Process 1 (%d) has got a signal from process 2 (%d)\n»,pid1,pid2); sleep(1); kill(pid2, SIGUSR2); return 0; } int f2(int signum) { signal(SIGUSR2, f2); printf(«Process 2 (%d) has got a signal from process 1 (%d)\n»,pid2,pid1); sleep(1); kill(pid1, SIGUSR1); return 0; } int f3(int signum) { printf(«End of job - %d\n», pid0); kill(0, SIGKILL); return 0; } Взаємодія процесів у LINUX Пакет IPC (Interprocess communication) містить у собі три механізми. Механізм повідомлень дає процесам можливість посилати іншим процесам потоки форматованих даних, механізм поділу пам'яті дозволяє процесам спільно використати окремі частини віртуального адресного простору, а семафори – синхронізувати своє виконання з виконанням паралельних процесів. Незважаючи на те, що вони реалізуються у вигляді окремих блоків, вони мають загальні властивості. Для використання механізмів IPC необхідно підключити до програми файл <sys/ipc.h>
|
||||
Последнее изменение этой страницы: 2016-04-26; просмотров: 618; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 18.221.248.140 (0.012 с.) |