АвтоАвтоматизацияАрхитектураАстрономияАудитБиологияБухгалтерияВоенное делоГенетикаГеографияГеологияГосударствоДомДругоеЖурналистика и СМИИзобретательствоИностранные языкиИнформатикаИскусствоИсторияКомпьютерыКулинарияКультураЛексикологияЛитератураЛогикаМаркетингМатематикаМашиностроениеМедицинаМенеджментМеталлы и СваркаМеханикаМузыкаНаселениеОбразованиеОхрана безопасности жизниОхрана ТрудаПедагогикаПолитикаПравоПриборостроениеПрограммированиеПроизводствоПромышленностьПсихологияРадиоРегилияСвязьСоциологияСпортСтандартизацияСтроительствоТехнологииТорговляТуризмФизикаФизиологияФилософияФинансыХимияХозяйствоЦеннообразованиеЧерчениеЭкологияЭконометрикаЭкономикаЭлектроникаЮриспунденкция

Взаємодія процесів. Розподілювана пам’ять. Семафори

Читайте также:
  1. Взаємодія АЕС і навколишнього середовища
  2. Взаємодія ГЕС і навколишнього середовища
  3. Взаємодія з іншими засобами
  4. Взаємодія країн у справі збереження та відновлення довкілля.
  5. Взаємодія металів з кислотами
  6. Взаємодія металів з неметалами
  7. Взаємодія митних органів з правоохоронними та іншими державними органами
  8. Взаємодія між органами Держказначейства та державної податкової служби в процесі виконання державного та місцевих бюджетів за доходами
  9. Взаємодія попиту і пропозиції. Ринкова рівновага та механізм її досягнення
  10. Взаємодія теорії та практики
  11. Взаємодія ТЕС і навколишнього середовища

Для синхронізації процесів, а точніше, для синхронізації доступу декількох процесів до ресурсів, що розділяються, використовуються семафори. Будучи однією з форм IPC, семафори не призначені для обміну великими об'ємами даних, як у разі FIFO або черг повідомлень. Натомість, вони виконують функцію, повністю відповідну своїй назві – дозволяти або забороняти процесу використання того або іншого ресурсу, що розділяється.

Застосування семафорів пояснимо на простому прикладі. Припустимо, є ресурс, що розділяється (наприклад, файл). Необхідно блокувати доступ до ресурсу для інших процесів, коли якийсь процес проводить операцію над ресурсом (наприклад, записує у файл). Для цього пов'яжемо з даним ресурсом якусь цілочисельну величину – лічильник, доступний для всіх процесів. Приймемо, що значення 1 лічильника означає доступність ресурсу, 0 ‑ його недоступність. Тоді перед початком роботи з ресурсом процес повинен перевірити значення лічильника. Якщо воно дорівнює нулю – ресурс зайнятий і операція недопустима – процесу залишається чекати. Якщо значення лічильника дорівнює 1 - можна працювати з ресурсом. Для цього, перш за все, необхідно заблокувати ресурс, тобто змінити значення лічильника на 0. Після виконання операції для звільнення ресурсу значення лічильника необхідно змінити на 1. У приведеному прикладі лічильник грає роль семафора.

Для нормальної роботи необхідно забезпечити виконання наступних умов:

1. Значення семафора повинне бути доступно різним процесам. Тому семафор знаходиться не в адресному просторі процесу, а в адресному просторі ядра.

2. Операція перевірки і зміни значення семафора повинна бути реалізована у вигляді однієї атомарної по відношенню до інших процесів (тобто безперервної іншими процесами) операції. Інакше можлива ситуація, коли після перевірки значення семафора виконання процесу буде перервано іншим процесом, який в свою чергу перевірить семафор і змінить його значення. Єдиним способом гарантувати атомарність критичних ділянок операцій є виконання цих операцій в режимі ядра.

Таким чином, семафори є системним ресурсом, дії над яким проводяться через інтерфейс системних викликів. Семафори в System V володіють наступними характеристиками:



· Семафор є не одним лічильником, а групою, що складається з декількох лічильників, об'єднаних ознаками (наприклад, дескриптором об'єкту, правами доступу і т. д.)

· Кожне з цих чисел може приймати будь-яке ненегативне значення в межах, визначених системою (а не тільки значення 0 або 1).

· Для кожної групи семафорів (надалі ми називатимемо групу просто семафором) ядро підтримує структуру даних semid_ds, що включає наступні поля:

struct ipc_perm sem_perm Опис прав доступу

struct sem *sem_base Покажчик на перший елемент масиву семафорів

ushort sem_nsems Число семафорів в групі

time_t sem_otime Час останньої операції

Значення конкретного семафора з набору зберігається у внутрішній структурі sem:

ushort semval Значення семафора

pid_t semid Ідентифікатор процесу, що виконав останню операцію над семафором.

ushort semncnt Число процесів, чекаючих

збільшення значення семафора.

ushort semzcnt Число процесів, чекаючих

обнулення семафора.

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

Для отримання доступу до семафора (і для його створення, якщо він не існує) використовується системний виклик semget():

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/sem.h>

int semget(key_t key,int nsems,int semflag);

У разі успішного завершення операції функція повертає дескриптор об'єкту, у разі невдачі ‑ -1.

Аргумент nsems задає число семафорів в групі. У разі, коли ми не створюємо, а лише дістаємо доступ до існуючого семафора, цей аргумент ігнорується. Аргумент semflag визначає права доступу до семафора і прапорці для його створення (IPC_CREAT, IPC_EXCL).

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

#include<sys/types.h>

#include<sys/ipc.h>

#include<sys/sem.h>

int semop(int semid,struct sembuf *semop,size_t nops);

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

Кожен елемент набору операцій semop має вигляд:

struct sembuf {

short sem_num; /* номер семафора в групі */

short sem_op; /* операція */

short sem_flg; /* прапори операції */

};

UNIX допускає три можливі операції над семафором, визначувані полем semop:

1. Якщо величина sem_op позитивна, то поточне значення семафора збільшується на цю величину.

2. Якщо значення sem_op дорівнює нулю, процес чекає, поки семафор не обнулиться.

3. Якщо величина sem_op негативна, процес чекає, поки значення семафора не стане більшим або рівним абсолютній величині semop. Потім абсолютна величина semop віднімається з значення семафора.

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

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

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

Як приклад, розглянемо два випадки використання бінарного семафора (тобто значення якого можуть приймати тільки 0 або 1). У першому прикладі значення 0 є таким, що відпирає, а 1 замикає деякий ресурс (файл, пам'ять, що розділяється, і т. п.), асоціюється з семафором. Визначимо операції, що замикають ресурс і що звільняють його:

static struct sembuf sop_lock[2]={

0,0,0 /* чекати обнулення семафора */

0,1,0 /* потім збільшити значення семафора на 1*/

};

static struct sembuf sop_unlock[1]={

0-1,0 /*обнулити значення семафора*/

};

Отже, для замикання ресурсу процес проводить виклик:

semop(semid,&sop_lock[0],2);

що забезпечує атомарне виконання двох операцій:

1. Очікування доступності ресурсу. У випадку, якщо ресурс вже зайнятий (значення семафора рівне 1), виконання процесу буде припинено до звільнення ресурсу (значення семафора рівне 0).

2. Замикання ресурсу. Значення семафора встановлюється рівним 1.

Для звільнення ресурсу процес повинен провести виклик:

semop(semid &sop_unlock[0],1);

який зменшить поточне значення семафора (рівне 1) на 1, і воно стане рівним 0, що відповідає звільненню ресурсу. Якщо якого-небудь з процесів чекає ресурс (тобто провів виклик операції sop_lock), він буде «розбуджений» системою, і зможе, у свою чергу, замкнути ресурс і працюватиз ним.

У другому прикладі змінимо трактування значень семафора: значенню 1 семафора відповідає доступність деякого асоційованого з семафором ресурсу, а нульовому значенню – його недоступність. В цьому випадку зміст операцій дещо зміниться.

static struct sembuf sop_lock[2]={

0-1,0, /* очікувати вирішуючого сигналу(1), потім обнулити семафор*/

};

static struct sembuf sop_unlock[1]={

0,1,0 /* з більшити значення семафора на 1*/

};

Процес замикає ресурс викликом:

semop(semid,&sop_lock[0],1);
а звільняє|:

semop(semid,&sop_unlock[0],1);

У другому випадку операції вийшли простіше (принаймні їх код став компактнішим), проте цей підхід має потенційну небезпеку: при створенні семафора, його значення встановлюються рівними 0, і в другому випадку він відразу ж замикає ресурс. Для подолання даної ситуації процес, першим що створив семафор, повинен і викликати операцію sop_unlock, проте в цьому випадку процес ініціалізації семафора перестане бути атомарним і може бути перерваний іншим процесом, який, у свою чергу, змінить значення семафора. У результаті, значення семафора стане рівним 2, що пошкодить нормальній роботіз ресурсом, що розділяється.

Можна запропонувати наступне рішення даної проблеми:

/*Створюємо семафор, якщо він вже існує semget() повертає помилку, оскільки вказаний прапор IPC_EXCL*/

if((semid=senget(key,nsems,perms|IPC_CREAT|IPC_EXCL))<0)

{

if(errno==EEXIST)

{

/*Дійсно, помилка викликана існуванням об’єкта */

if((semid=senget(key,nsems,perms))<0)

return (-1); /* Можливо не вистачає системних ресурсів */

}

else return (-1); /* Можливо, не вистачає системних ресурсів */

}

/*Якщо семафор створений нами, проініціалізуємо його*/

else semop(semid,&sop_unlock[0],1);

 




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