Заглавная страница Избранные статьи Случайная статья Познавательные статьи Новые добавления Обратная связь FAQ Написать работу КАТЕГОРИИ: АрхеологияБиология Генетика География Информатика История Логика Маркетинг Математика Менеджмент Механика Педагогика Религия Социология Технологии Физика Философия Финансы Химия Экология ТОП 10 на сайте Приготовление дезинфицирующих растворов различной концентрацииТехника нижней прямой подачи мяча. Франко-прусская война (причины и последствия) Организация работы процедурного кабинета Смысловое и механическое запоминание, их место и роль в усвоении знаний Коммуникативные барьеры и пути их преодоления Обработка изделий медицинского назначения многократного применения Образцы текста публицистического стиля Четыре типа изменения баланса Задачи с ответами для Всероссийской олимпиады по праву Мы поможем в написании ваших работ! ЗНАЕТЕ ЛИ ВЫ?
Влияние общества на человека
Приготовление дезинфицирующих растворов различной концентрации Практические работы по географии для 6 класса Организация работы процедурного кабинета Изменения в неживой природе осенью Уборка процедурного кабинета Сольфеджио. Все правила по сольфеджио Балочные системы. Определение реакций опор и моментов защемления |
Системні виклики для роботи із семафорами↑ ⇐ ПредыдущаяСтр 4 из 4 Содержание книги
Поиск на нашем сайте
Системні виклики для роботи із семафорами в ОС Linux описані в бібліотеці <sys/sem.h>. SEMGET Створення набору семафорів і одержання доступу до них: int semget(key_t key, int count, int semflg); semid = semget(key, count, semflg); де key – номер семафора, count – кількість семафорів, semflg – параметри створення і права доступу. Ядро використовує key для ве-дення пошуку в таблиці семафорів: якщо підходящий запис виявлений і дозвіл на доступ є, ядро повертає викликаючому процесу зазначений у записі дескриптор. Якщо запис не знайдений, а користувач установив прапорець IPC_CREAT – створення нового семафора – ядро перевіряє можливість його створення і виділяє запис у таблиці семафорів. Запис вказує на масив семафорів і містить лічильник count. У записі також зберігається кількість семафорів у масиві, час останнього виконання функцій semop й semctl. SEMOP Установка або перевірка значення семафора: int semop(int semid, struct sembuf *oplist, unsigned nsops); де semid – дескриптор, що повертається функцією semget, oplist – покажчик на список операцій, nsops – розмір списку. Значення, що повертається функцією, є старим значенням семафора, над яким проводилась операція. Кожен елемент списку операцій має наступний формат (визначення структури sembuf у файлі sys/sem.h): struct sembuf { unsigned short sem_num; short sem_op; short sem_flg; } де shortsem_num – номер семафора, що ідентифікує елемент масиву семафорів, над яким виконується операція; sem_op – код операції; sem_fl – прапорці операції. Ядро зчитує список операцій oplist з адресного простору задачі та перевіряє коректність номерів семафорів, а також наявність у процесу необхідних дозволів на читання і коректування семафорів. Якщо таких дозволів немає, системна функція завершується невдало (res = –1). Якщо ядру доводиться припиняти свою роботу при звертанні до списку операцій, воно повертає семафорам їхні колишні значення та перебуває в стані призупинки до настання очікуваної події, після чого системна функція запускається знову. Оскільки ядро зберігає коди операцій над семафорами в глобальному списку, воно знову зчитує цей список із простору завдання, коли перезапускає системну функцію. Таким чином, операції виконуються комплексно – або всі за один сеанс, або жодної. Установка прапорця IPC_NOWAIT у функції semop має наступний сенс: якщо ядро попадає в таку ситуацію, коли процес повинен призупинити своє виконання, чекаючи збільшення значення семафора вище певного рівня або, навпаки, зниження цього значення до 0, і якщо при цьому прапор IPC_NOWAIT установлений, ядро виходить із функції з повідомленням про помилку. (Таким чином, якщо не припиняти процес у випадку неможливості виконання окремої операції, можна реалізувати умовний тип семафора). Прапор SEM_UNDO дозволяє уникнути блокування семафора процесом, що закінчив свою роботу, перш ніж звільнив захоплений ним семафор. Якщо процес установив прапор SEM_UNDO, то при завершенні цього процесу ядро дасть зворотний хід всім операціям, виконаних процесом. Для цього в розпорядженні в ядра є таблиця, у якій кожному процесу відведений окремий запис. Запис містить покажчик на групу структур відновлення, по одній структурі на кожен використовуваний процесом семафор. Кожна структура відновлення складається із трьох елементів – ідентифікатора семафора, його порядкового номера в наборі та установочного значення. Ядро виділяє структури відновлення динамічно, під час першого виконання системної функції semop із встановленим прапором SEM_UNDO. При наступних звертаннях до функції з тим самим прапором ядро переглядає структури відновлення для процесу в пошуках структури з тим самим ідентифікатором і порядковим номером семафора, що й у виклику функції. Якщо структура виявлена, ядро віднімає значення зробленої над семафором операції з установочного значення. Таким чином, у структурі відновлення зберігається результат вирахування суми значень всіх операцій, зроблених над семафором, для якого встановлений прапорець SEM_UNDO. Якщо відповідної структури немає, ядро створює її, сортуючи при цьому список структур по ідентифікаторах і номерам семафорів. Якщо установочне значення стає рівним 0, ядро видаляє структуру зі списку. Коли процес завершується, ядро викликає спеціальну процедуру, що переглядає всі пов’язані із процесом структури відновлення й виконує над зазначеним семафором всі обумовлені дії. Ядро міняє значення семафора залежно від коду операції, зазначеного у виклику функції semop. Якщо код операції має позитивне значення, ядро збільшує значення семафора і виводить зі стану призупинки всі процеси, що очікують настання цієї події. Якщо код операції дорівнює 0, ядро перевіряє значення семафора: якщо воно дорівнює 0, ядро переходить до виконання інших операцій; в іншому випадку ядро збільшує число припинених процесів, що очікують, коли значення семафора стане нульовим, і “засинає”. Якщо код операції негативний та його абсолютне значення не перевищує значення семафора, ядро додає код операції (негативне число) до значення семафора. Якщо результат дорівнює 0, ядро виводить зі стану призупинки всі процеси, що очікують обнуління значення семафора. Якщо результат менше абсолютного значення коду операції, ядро припиняє процес доти, поки значення семафора не збільшиться. Якщо процес припиняється посередині операції, він має пріоритет, що допускає переривання; отже, одержавши сигнал, він виходить із цього стану. SEMCTL Виконання керуючих операцій над набором семафорів: int semctl(int semid, int semnum, int cmd, union semun arg); Параметр arg оголошений як об’єднання типів даних: union semunion { int val; // використовується тільки для SETVAL struct semid_ds *semstat; // для IPC_STAT й IPC_SET unsigned short *array; } arg; Ядро інтерпретує параметр arg залежно від значення параметра cmd, що може приймати наступні значення: – GETVAL – повернути значення того семафора, на який вказує параметр num; – SETVAL – установити значення семафора, на який вказує параметр num, рівним значенню arg.val; – GETPID – повернути ідентифікатор процесу, що виконував останнім функцію semop стосовно того семафора, на який вказує параметр semnum; – GETNCNT – повернути число процесів, що очікують того моменту, коли значення семафора стане позитивним; – GETZCNT – повернути число процесів, що очікують того моменту, коли значення семафора стане нульовим; – GETALL – повернути значення всіх семафорів у масиві arg.array; – SETALL – установити значення всіх семафорів відповідно до вмісту масиву arg.array; – IPC_STAT – зчитати структуру заголовку семафора з ідентифікатором id у буфер arg.buf. Аргумент semnum ігнорується; – IPC_SET – запис структури семафора з буфера arg.buf; – IPC_RMID – видалити семафори, пов’язані з ідентифікатором id, із системи. Якщо зазначено команду видалення IPC_RMID, ядро веде пошук всіх процесів, що містять структури відновлення для даного семафора, і видаляє відповідні структури із системи. Потім ядро ініціалізує використовувані семафором структури даних і виводить зі стану призупинки всі процеси, що очікують настання деякої пов’язаної з семафором події: коли процеси відновлюють своє виконання, вони виявляють, що ідентифікатор семафора є не коректним, і повертають викликаючій програмі помилку. Якщо число, що повертається функцією, дорівнює 0, то функція завершилася успішно, інакше (повертається значення, що дорівнює –1) відбулася помилка. Код помилки зберігається в змінній errno. Приклад запису в область поділюваної пам’яті й читання з неї. Перша із програм описує процес, у якому створюється область поділюваної пам’яті розміром 128 Кбайт і проводиться запис і зчитування даних із цієї області. Другий процес приєднує ту саму область (він одержує тільки 64 Кбайт, таким чином, кожен процес може використати різний обсяг області поділюваної пам’яті); він чекає моменту, коли перший процес запише в перше приналежне області слово будь-яке відмінне від нуля значення, і потім починає зчитувати дані з області. Перший процес робить “паузу” (pause), надаючи другому процесу можливість виконання; коли перший процес приймає сигнал, він видаляє область поділюваної пам’яті із системи. /*Запис у поділювану пам'ять і читання з неї*/ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define SHMKEY #define K 1024 int shmid; main() { int i, *pint; char *addr; extern char *shmat(); extern cleanup(); /* визначення реакції на всі сигнали */ for (i = 0; i < 20; i++) signal(i, cleanup); /* створення загальнодоступної поділюваної області пам'яті розміром 128*K (або одержання її ідентифікатора, якщо вона вже існує)*/ shmid = shmget(SHMKEY,128*K,0777:IPC_CREAT); addr = shmat(shmid,0,0); pint = (int *) addr; for (i = 0; i < 256; i++) *pint++ = i; pint = (int *) addr; *pint = 256; pint = (int *) addr; for (i = 0; i < 256; i++) printf(“index %d\tvalue %d\n”,i,*pint++); /* очікування сигналу */ pause(); } /* видалення поділюваної пам'яті */ cleanup() { shmctl(shmid,IPC_RMID,0); exit(); } /*Читання з поділюваної пам’яті даних, записаних першим процесом */ #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #define SHMKEY 75 #define K 1024 int shmid; main() { int i, *pint; char *addr; extern char *shmat(); shmid = shmget(SHMKEY,64*K,0777); addr = shmat(shmid,0,0); pint = (int *) addr; while (*pint == 0); /* очікування початку запису */ for (i = 0; i < 256, i++) printf(“%d\n”,*pint++); } Приклад роботи двох паралельних процесів в одному критичному інтервалі часу. Для організації роботи двох процесів в одному критичному інтервалі часу необхідно на час роботи одного процесу зробити неможливим роботу іншого (тобто другий процес не може виконуватися одночасно з першим). Для цього використаємо засіб синхронізації – семафор. У цьому випадку нам буде потрібно один семафор. Опишемо його за допомогою системної функції ОС Linux: lsid = semget(75, 1, 0777 | IPC_CREAT); де lsid – це ідентифікатор семафора; 75 – ключ використо-вуваного дескриптора (якщо він зайнятий, система створить свій); 1 – кількість семафорів у масиві; IPC_CREAT – прапор для створення нового запису в таблиці дескрипторів (описаний із правами доступу 0777). Для установки початкового значення семафора використаємо структуру sem. У ній присвоюємо значення: sem.array[0] = 1; тобто семафор відкритий для користування. Завершальним кроком є ініціалізація масиву (у цьому випадку масив складається з одного елемента): semctl(lsid,1,SETALL,sem); де lsid – ідентифікатор семафора (виділений рядок у дескрипторі); 1 – кількість семафорів; SETALL – команда “установити всі семафори”; sem – покажчик на структуру. Установлюємо прапор SEM_UNDO у структурі sop для роботи з функцією semop (значення цього прапора не міняється в процесі роботи). Далі в програмі організуються два паралельних процеси (нащадки “головної” програми) за допомогою системної функції fork(). Один процес-нащадок записує дані в поділювану пам’ять, другий зчитує ці дані. При цьому процеси-нащадки синхронізують доступ до поділюваної пам’яті за допомогою семафорів. Функція p () описується в такий спосіб: int p(int sid) { sop.sem_num = 0; /* номер семафора */ sop.sem_op = -1; semop(sid, &sop, 1); } У структуру sop заноситься номер семафора, над яким буде виконана операція та значення самої операції (у цьому випадку це зменшення значення на 1). Прапорець був встановлений заздалегідь, тому функція в процесі завжди перебуває, чекаючи вільного семафора. (Функція v () працює аналогічно, але sop.sem_op = 1). Результатом виконання наведеної нижче програми є список повідомлень від процесів, що відповідає послідовності роботи процесів. #include <stdio.h> #include <sys/types.h> #include <sys/ipc.h> #include <sys/shm.h> #include <sys/sem.h> #include <unistd.h> #include <errno.h> int shmid, lsid, x; struct sembuf sop; union semun { int val; struct semid_ds *buf; ushort *array; } sem; int p(int sid) { sop.sem_num = 1; sop.sem_op = -1; semop(sid, &sop, 1); } int v(int sid) { sop.sem_num = 1; sop.sem_op = 1; semop(sid, &sop, 1); } main() { int j, i, id, id1, n; lsid = semget(75, 1, 0777 | IPC_CREAT); sem.array = (ushort*)malloc(sizeof(ushort)); sem.array[0] = 1; sop.sem_flg = SEM_UNDO; semctl(lsid, 1, SETALL, sem); printf(«n= «); scanf(«%d», &n); id = fork(); if (id == 0) /* перший процес */ { for(i = 0; i < n; i++) { p(lsid); puts(«\n Працює процес 1»); v(lsid); } exit(0); } id1 = fork(); if (id1 == 0) /* другий процес */ { for (j = 0; j < n; j++) { p(lsid); puts(«\n Працює процес 2»); v(lsid); } exit(0); } wait(&x); wait(&x); exit(0); } Завдання Завдання 1 1. Процес 1 породжує нащадка 2, що у свою чергу породжує нащадка 3. За допомогою сигналів домогтися того, щоб ці процеси закінчувалися в порядку 1, 2, 3. 2. Процес 1 породжує нащадка 2. Обидва процеси після цього відкривають той самий файл і пишуть у нього по черзі по N байт. Організувати M циклів запису за допомогою сигналів. 3. Процес 1 відкриває файл і після цього породжує нащадка 2. Процес 2 починає запис у файл після одержання сигналу SIG1 від процесу 1 і припиняє її після одержання від процесу 1 сигналу SIG2, що посилає через N секунд після SIG1. Потім процес 1 читає дані з файла і виводить їх на екран. 4. Процес 1 відкриває файл і після цього породжує нащадка 2. Один процес пише у файл один байт, посилає іншому процесу сигнал, інший читає з файла один байт, виводить прочитане на екран і посилає сигнал першому процесу. Організувати N циклів запису (читання). 5. Процес 1 відкриває файл і породжує нащадків 2 та 3. Нащадки після сигналу від предка пишуть у файл по N байт, посилають сигнали процесу 1 і завершують роботу. Після цього процес 1 зчитує дані з файла і виводить на екран. 6. Процес 1 відкриває файл і після цього породжує нащадка 2, що у свою чергу породжує нащадка 3. Процес 2 пише N байт у загальний файл, посилає сигнал процесу 3, що теж пише N байт у файл і посилає сигнал процесу 1, що зчитує дані з файла і виводить їх на екран. 7. Процес 1 відкриває файл і породжує нащадка 2, після цього пише у файл N байт і посилає сигнал процесу 2. Процес 2 пише N байт у файл, посилає сигнал процесу 1 і завершується. Процес 1, одержавши сигнал, зчитує дані з файла, виводить їх на екран і завершується. 8. Процес 1 породжує нащадка 2. Обидва процеси відкривають той самий файл і записують у нього в циклі по N байт. За допомогою сигналів організувати черговість запису. 9. Процес 1 відкриває файл і породжує нащадків 2 та 3. Нащадки пишуть у файл по черзі по N байт (M циклів запису, організувати за допомогою сигналів) і завершуються. Останній з них посилає сигнал процесу 1, що читає дані та виводить їх на екран. 10. Процес 1 відкриває файл, породжує нащадка 2, пише у файл N байт і посилає сигнал SIG1 процесу 2. Процес 2 за сигналом SIG1 читає дані, виводить їх на екран і завершується. Якщо сигнал від процесу 1 не надійде протягом M секунд, процес 2 починає зчитувати дані за сигналом SIGALRM. 11. Процес 1 відкриває файл і породжує нащадка 2, що у свою чергу породжує нащадка 3. Процеси 2 та 3 пишуть у загальний файл, причому процес 3 не може почати писати раніше, ніж процес 2. Організувати черговість за допомогою сигналів. Як тільки розмір файла перевищить N байт, процес 1 посилає нащадкам сигнал SIG2 про завершення роботи, зчитує дані з файла і виводить їх на екран. 12. Процес 1 відкриває файл і породжує нащадка 2. Процес 1 з інтервалом в 1 секунду (через alarm) посилає M сигналів SIG1 процесу 2, що за кожним сигналом пише в загальний файл по N чисел. Потім процес 1 посилає процесу 2 сигнал SIG2, процес 2 завершується. Процес 1 зчитує дані з файла і виводить їх на екран. 13. Процес 1 відкриває файл і породжує нащадків 2 та 3. Процес 1 з інтервалом в 1 секунду (через alarm) по черзі посилає N сигналів SIG1 процесам 2 та 3, які за кожним сигналом пишуть у загальний файл по M чисел. Потім процес 1 посилає нащадкам сигнал SIG2, процеси 2 та 3 завершуються. Процес 1 зчитує дані з файла і виводить їх на екран. 14. Процес 1 відкриває два файли і породжує нащадків 2 та 3. Процеси 2 та 3 з інтервалом в 1 секунду (через alarm) посилають по N сигналів процесу 1, що за кожним сигналом пише у відповідний файл по M чисел. Потім процеси 2 та 3 зчитують дані з файлів, виводять їх на екран і завершуються. Процес 1 завершується останнім. 15. Процес 1 відкриває два файли й породжує нащадків 2 та 3. Процеси 2 та 3 посилають по одному сигналі процесу 1, що за кожним сигналом пише у відповідний файл M чисел. Процеси 2 та 3 зчитують дані з файлів і виводять їх на екран. За допомогою сигналів організувати непересічний вивід даних. 16. Процес 1 відкриває файл і породжує нащадка 2. Процес 2 за сигналом SIG1 від процесу 1 починає писати у файл, за сигналом SIG2 припиняє запис, а потім за сигналом SIG1 завершується. Сигнал SIG1 надходить із затримкою в 1 секунду щодо першого сигналу SIG2. 17. Процес 1 відкриває файл і породжує нащадка 2. Процес 1 читає дані з файла, процес 2 пише дані у файл у такий спосіб: за сигналом SIG1 від процесу 1 процес 2 записує у файл N чисел і посилає процесу 1 сигнал закінчення запису; процес 1 за цим сигналом зчитує дані і посилає процесу 2 сигнал SIG1. Процес 2 завжди пише дані в початок файла. Організувати M циклів запису (читання). Прочитані дані виводяться на екран. 18. Процес 1 відкриває існуючий файл і породжує нащадка 2. Процес 1 зчитує N байт із файла, виводить їх на екран і посилає сигнал SIG1 процесу 2. Процес 2 також зчитує N байт із файла, виводить їх на екран і посилає сигнал SIG1 процесу 1. Якщо одному із процесів зустрівся кінець файла, то він посилає іншому процесу сигнал SIG2 і вони обоє завершуються. 19. Процес 1 відкриває файл і породжує нащадка 2. Обидва процеси пишуть у нього по черзі по N чисел. Організувати M циклів запису за допомогою сигналів. 20. Процес 1 породжує нащадка 2. Процес 1 пише в загальний файл число 1, процес 2 – число 2. Використовуючи сигнали, забезпечити наступний вміст файла: а) 1 2 1 2 1 2 1 2 б) 1 1 2 2 1 1 2 2 в) 1 1 2 1 1 2 1 1 2 г) 2 1 1 2 1 1 2 1 1 д) 1 2 2 1 2 2 1 2 2 Завдання 2 1. Процес 1 породжує нащадків 2 та 3, всі вони приєднують до себе поділювану пам’ять обсягом (2*sizeof(int)). Процеси 1 та 2 по черзі пишуть у цю пам’ять число, рівне своєму номеру (1 або 2). Після Цього один з процесів видаляє поділювану пам’ять, потім процес 3 зчитує вміст області поділюваної пам’яті та записує у файл. Використовуючи семафори, забезпечити наступний вміст файла: а) 1 2 1 2 1 2 1 2 б) 1 1 2 2 1 1 2 2 в) 1 1 2 1 1 2 1 1 2 г) 2 1 1 2 1 1 2 1 1 д) 1 2 2 1 2 2 1 2 2 2. Процес 1 породжує нащадків 2 та 3. Всі процеси записують у загальну поділювану пам’ять число, рівне своєму номеру. Використовуючи семафори, забезпечити наступний вміст області пам’яті: а) 1 2 3 1 2 3 1 2 3 б) 1 1 2 2 3 3 1 1 2 2 3 3 в) 1 2 1 3 1 2 1 3 1 2 1 3 г) 2 1 1 3 2 1 1 3 2 1 1 3 д) 3 1 2 3 1 2 3 1 2 Останній процес зчитує вміст поділюваної пам’яті, виводить його на екран і видаляє поділювану пам’ять. 3. Процес 1 породжує нащадків 2 та 3, всі вони приєднують до себе дві області поділюваної пам’яті M1 та M2 обсягом (N1*sizeof(int)) і (N2*sizeof(int)) відповідно. Процес 1 пише в M1 число, що після кожного запису збільшується на 1; процес 2 переписує k2 чисел з M1 в M2, а процес 3 переписує k3 чисел з M2 у файл. Після кожного етапу роботи процес 1 засинає на t1 секунд, процес 2 – на t2 секунд, а процес 3 – на t3 секунд. Процесу 1 забороняється записувати в зайняту область M1; процес 2 може переписати дані, якщо був зроблений запис в M1 та M2 вільна; процес 3 може переписувати дані з M2, тільки якщо був здійснений запис в M2. Використовуючи семафори, забезпечити синхронізацію роботи процесів відповідно до заданих умов. Параметри N1, N2, k1, k2, k3, t1, t2, t3 задаються у вигляді аргументів командного рядка. 4. Процес 1 породжує нащадка 2, вони приєднують до себе поділювану пам’ять обсягом (N*sizeof(int)). Процес 1 пише в неї k1 чисел відразу, процес 2 переписує k2 чисел з пам’яті у файл. Процес 1 може робити запис, тільки якщо в пам’яті досить місця, а процес 2 переписувати, тільки якщо є не менше, ніж k2 чисел. Після кожного запису (читання) процеси засинають на t секунд. Після кожного запису процес 1 збільшує значення записуваних чисел на 1. Використовуючи семафори, забезпечити синхронізацію роботи процесів відповідно до заданих умов. Параметри N, k1, k2, t задаються у вигляді аргументів командного рядка. Контрольні питання 1. Команди для роботи з процесами. 2. Базові сигнали операційної системи Linux. 3. Системні виклики для роботи з сигналами. 4. Стани процесу і переходи між ними. 5. Групи процесів. 6. Системні виклики для роботи з процесами. 7. Використання поділюваної пам’яті. 8. Синхронізація процесів. 9. Семафори та їх реалізація.
|
||||
Последнее изменение этой страницы: 2016-04-26; просмотров: 347; Нарушение авторского права страницы; Мы поможем в написании вашей работы! infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.133.148.117 (0.013 с.) |