Міжпроцесова взаємодія

Матеріал з Фізмат Вікіпедії
Перейти до: навігація, пошук

Міжпроцесова взаємодія

  • Проблеми міжпроцесової взаємодії
  • Види міжпроцесової взаємодії
  • Принципи та базові примітиви передавання повідомлень
  • Технології передавання повідомлень

Дотепер ми розглядали взаємодію потоків одного процесу. Головною особливістю цієї взаємодії є простота технічної реалізації обміну даними між ними — усі пото­ ки одного процесу використовують один адресний простір, а отже, можуть вільно отримувати доступ до спільно використовуваних даних, ніби вони є їх власними. Оскільки технічних труднощів із реалізацією обміну даними тут немає, основною проблемою, яку потрібно вирішувати в цьому випадку, є синхронізація потоків. З іншого боку, кожен потік виконується в рамках адресного простору деякого процесу, тому часто постає задача організації взаємодії між потоками різних про­ цесів. Ідеться власне про міжпроцесову взаємодію (interprocess communication, IPC) [37]. Ця технологія з'явилася задовго до поширення багатопотоковості. Для потоків різних процесів питання забезпечення синхронізації теж є акту­ альними, але вони в більшості випадків не ґрунтуються на понятті спільно вико­ ристовуваних даних (такі дані за замовчуванням для процесів відсутні). Крім того, додається досить складна задача забезпечення обміну даними між захищеними адресними просторами. Підходи до її розв'язання визначають різні види міжпро­ цесової взаємодії.

Види міжпроцесової взаємодії

Реалізація міжпроцесової взаємодії здійснюється трьома основними методами: передавання повідомлень, розподілюваної пам'яті та відображуваної пам'яті. Ще одним методом IPC також можна вважати технологію сигналів, що була розгля­ нута в розділі 3. Сигнали були розглянуті раніше, тому що їхнє використання не зводиться тільки до організації IPC (синхронні сигнали є засобом оповіщення процесу про виняткову ситуацію); без них складно пояснити ряд базових понять керування процесами (наприклад, очікування завершення процесу).

Методи розподілюваної пам'яті

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

Методи передавання повідомлень

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

Технологія відображуваної пам'яті

Ще однією категорією засобів міжпроцесової взаємодії є відображувана пам'ять (mapped memory). У ряді ОС відображувана пам'ять є базовим системним механіз­ мом, на якому ґрунтуються інші види міжпроцесової взаємодії та системні вирі­ шення. Звичайно відображувану пам'ять використовують у поєднанні з інтерфей­ сом файлової системи, в такому разі говорять про файли, відображувані у пам'ять (memory-mapped files). Ця технологія зводиться до того, що за допомогою спеціального системного виклику (зазвичай це mmapO) певну частину адресного простору процесу одно­ значно пов'язують із вмістом файла. Після цього будь-яка операція записування в таку пам'ять спричиняє зміну вмісту відображеного файла, яка відразу стає доступною усім застосуванням, що мають доступ до цього файла. Інші застосу­ вання теж можуть відобразити той самий файл у свій адресний простір і обміню­ ватися через нього даними один з одним. Файли, відображувані у пам'ять, будуть докладно розглянуті в розділі 11.

Особливості міжпроцесової взаємодії

Тепер можна порівняти характеристики міжпроцесової взаємодії із характерис­ тиками взаємодії потоків одного процесу.

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

Базові механізми міжпроцесової взаємодії

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

Міжпроцесова взаємодія на базі спільної пам'яті

Для вирішення проблеми міжпроцесової синхронізації необхідно:

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

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

Основи передавання повідомлень

Усі методи взаємодії, які було розглянуто дотепер, ґрунтуються на читанні й запи­ суванні спільно використовуваних даних. На практиці така взаємодія не завжди можлива (наприклад, робота зі спільно використовуваними даними проблема­ тична, якщо для процесів немає спільної фізичної пам'яті, а є тільки мережний зв'язок між комп'ютерами, на яких вони виконуються). У таких випадках можна використати засоби взаємодії, які не ґрунтуються на спільно використовуваних даних, передусім засоби передавання повідомлень [27, 37, 57]. Як було вже згадано, засоби передавання повідомлень ґрунтуються на обміні повідомленнями — фрагментами даних змінної довжини. Основою такого обмі­ ну є не спільна пам'ять, а канал зв'язку (communication channel). Він забезпечує взаємодію між процесами (для того, щоб спілкуватися, вони повинні створи­ ти канал зв'язку) і є абстрактним відображенням мережі зв'язку. Абстрактність каналу дає змогу реалізувати його не тільки на основі мережної взаємодії, але й спільної пам'яті (коли процеси перебувають на одному Виокремлюють такі характеристики каналів зв'язку: спосіб задання; кількість процесів, які можуть бути з'єднані одним каналом; кількість каналів, які можуть бути створені між двома процесами; пропускна здатність каналу (кількість пові­ домлень, які можуть одночасно перебувати в системі й бути асоційованими з цим каналом); максимальний розмір повідомлення; спрямованість зв'язку через ка­ нал (двобічний або однобічний зв'язок). В однобічному зв'язку для конкретного процесу допускають передавання да­ них тільки в один бік. Примітиви передавання повідомлень Основна особливість передавання повідомлень полягає в тому, що процеси спіль­ но використовують тільки канали. Немає необхідності забезпечувати взаємне ви­ ключення процесів під час доступу до спільно використовуваних даних, замість цього досить визначити примітиви передавання повідомлень — спеціальні опера­ ції обміну даними через канал, які забезпечують не лише обмін даними, але й син­ хронізацію. Є два примітиви передавання повідомлень: send (для відсилання повідомлен­ ня каналом) і гесеі ve (для отримання повідомлення з каналу). Розглянемо, як особливості реалізації send і гесеі ve дають змогу виділити різ­ ні класи методів передавання повідомлень. Зазначені примітиви передавання повідомлень можуть задавати прямий і не­ прямий обмін даними. При прямому обміні даними необхідно явно вказувати процес, з яким необхідно обмінюватись інформацією. Непрямий обмін здійснюють через спеціальний об'єкт (поштову скриньку, порт); процеси можуть поміщати повідомлення в поштову скриньку і отримувати їх звідти. Зазвичай кілька процесів мають доступ до однієї поштової скриньки, застосовуючи під час її пошуку мето­ ди іменування. Більшість сучасних технологій обміну повідомленнями використо­ вує непрямий обмін даними. Прикладом прямого обміну є традиційні сигнали. Синхронне й асинхронне передавання повідомлень Зупинимося на основних питаннях синхронізації під час передавання повідомлень. Можна виокремити різні групи методів передавання повідомлень залежно від то­ го, як вони дають можливість відповісти на два запитання.

  1. Чи може потік бути призупинений під час виконання операції send, якщо пові­ домлення не було отримане?
  2. Чи може потік бути призупинений під час виконання операції гесеі ve, якщо повідомлення не було відіслане?

У реальних системах відповідь на друге запитання практично завжди буде по­ зитивною — неблокувальне приймання повідомлень спричиняється до того, що вони губляться. Варіанти відповідей на перше запитання визначають два класи передавання повідомлень — синхронне і асинхронне. Під час синхронного передавання повідомлень операція send призупиняє про­ цес до отримання повідомлення, а під час асинхронного передавання повідомлень вона не призупиняє процес (тобто є неблоку вальною); після відсилання повідомлення процес продовжує своє виконання, не чекаючи отримання результату. Найзручні­ ше в цьому випадку використати непряму Реалізація синхронного й асинхронного передавання повідомлень залежить від низки характеристик каналу й обміну повідомленнями, насамперед від пропуск­ ної здатності каналу.

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

Під час обміну повідомленнями необхідне підтвердження їх отримання. Деякі методи обміну повідомленнями не вимагають підтвердження зовсім, в інших ви­ падках можлива ситуація, коли відправника після виконання операції send блоку­ ють доти, поки одержувач не надішле йому інше повідомлення із підтвердженням отримання; таку технологію називають обміном повідомленнями із підтверджен­ ням отримання. Розв'язання задачі виробників-споживачів за допомогою передавання повідомлень Розглянемо розв'язання задачі виробників-споживачів із використанням асин­ хронного передавання повідомлень. Організовують дві поштові скриньки — для виробника і для споживача. Якщо скринька порожня, потік очікуватиме, поки в ній не з'явиться повідомлення. Поштові скриньки виробника та споживача мають свої особливості. Скринька виробника може містити тільки порожні повідомлення загальною кількістю не більше п. Наявність т повідомлень у цій скриньці служить сигналом для виробника, що в буфері є місце для т об'єктів. Щоб відіслати дані в буфер, виробник забирає зі скриньки одне повідомлення, заповнює його даними і від­ силає в скриньку споживача. Заповнивши буфер, виробник спустошить свою скриньку і буде змушений чекати, поки споживач не помістить у неї порожнє по­ відомлення. Повідомлення у скриньці споживача відповідають об'єктам у буфері. Після того як споживач забере повідомлення з цієї скриньки, він використає його дані й відішле порожнє повідомлення у скриньку виробника, сигналізуючи, що в бу­ фері з'явилося місце. Порожня скринька споживача означає порожній буфер — споживач чекатиме, поки виробник не помістить заповнене повідомлення в цю скриньку. На початку роботи скриньку виробника заповнюють порожніми повідомлен­ нями загальним числом п (це буде означати, що він може зробити п об'єктів). Функції producer() ¡consumero схожі. І виробник, і споживач у циклі намага­ ються забрати повідомлення зі своїх скриньок. Якщо це вдається виробникові, він заповнює повідомлення даними і відсилає його у скриньку споживача, як­ що це сможе зробити споживач, він скористається повідомленням і відішле по­ рожнє повідомлення у скриньку виробника. Після цього цикл триває. Ось алгоритм розв'язання задачі:

message_t nulljnsg; // порожнє повідомлення mailbox_t producer_mai 1 box. consumerjnailbox; // поштові скриньки

int n = 100: // розмір буфера void producerO { message_t producerjnsg: for (;  ;) {

// забрати повідомлення зі скриньки виробника, // чекати, якщо вона порожня receive(producer_mai 1 box. producerjrisg); producerjnsg.data - producen; // відіслати заповнене повідомлення у скриньку споживача send(consumer_mailbox. producer_msg): } } void consumero { message_t consumerjnsg: for (; :) { II забрати повідомлення зі скриньки споживача, чекати якщо вона порожня receive(consumer_mailbox, consumerjnsg): consume(consumer_msg.data); // відіслати у скриньку виробника порожнє повідомлення // повідомивши йому про те. що у буфері є місце send(producer_mailbox, null _ msg); } } void mainC) { // заповнити скриньку виробника порожніми повідомленнями fortint і=0: і<п; і++) send(producer_mailbox, null _ msg): // запустити producerO i customerO паралельно } Основна відмінність цього розв'язання від запропонованих у розділі 5 поля­ гає в тому, що воно не залежить від спільно використовуваних даних. Доступ до поштових скриньок може бути виконаний за допомогою системних викликів, що приховують їхнє місцезнаходження; скриньки можуть бути й віддаленими. Це дає змогу застосовувати алгоритм тоді, коли виробник і споживач є різними про­ цесами, а можливо, й перебувають на різних комп'ютерах.

Технології передавання повідомлень

Розглянемо методи передавання повідомлень, які застосовують на практиці. Канали Канал — це найпростіший засіб передавання повідомлень. Він є циклічним буфе­ ром, записування у який виконують за допомогою одного процесу, а читання — за допомогою іншого. У конкретний момент часу до каналу має доступ тільки один процес. Операційна система забезпечує синхронізацію згідно правилу: якщо про­ цес намагається записувати в канал, у якому немає місця, або намагається зчита­ ти більше даних, ніж поміщено в канал, він переходить у стан очікування. Розрізняють безіменні та поіменовані канали. До безіменних каналів немає доступу за допомогою засобів іменування, тому процес не може відкрити вже наявний безіменний канал без його дескриптора. Це означає, що такий процес має отримати дескриптор каналу від процесу, що його створив, а це можливо тільки для зв'язаних процесів. До поіменованих каналів (named pipes) є доступ за іменем. Такому каналу мо­ же відповідати, наприклад, файл у файловій системі, при цьому будь-який про­ цес, який має доступ до цього файла, може обмінюватися даними через відповід­ ний канал. Поіменовані канали реалізують непрямий обмін даними. Обмін даними через канал може бути однобічним і двобічним. Приклади використання поіменованих каналів будуть наведені в розділі 11, безіменних — у розділі 17. Черги повідомлень Іншою технологією асинхронного непрямого обміну даними є застосування черг повідомлень (message queues) [37, 52]. Для таких черг виділяють спеціальне місце в системній ділянці пам'яті ОС, доступне для застосувань користувача. Процеси можуть створювати нові черги, відсилати повідомлення в конкретну чергу й от­ римувати їх звідти. Із чергою одночасно може працювати кілька процесів. Пові­ домлення — це структури даних змінної довжини. Для того щоб процеси могли розрізняти адресовані їм повідомлення, кожному з них присвоюють тип. Відісла­ не повідомлення залишається в черзі доти, поки не буде зчитане. Синхронізація під час роботи з чергами схожа на синхронізацію для каналів. Сокети Найрозповсюдженішим методом обміну повідомленнями є використання сокетів (sockets). Ця технологія насамперед призначена для організації мережного обмі­ ну даними, але може бути використана й для взаємодії між процесами на одному комп'ютері (власне, мережну взаємодію можна розуміти як узагальнення IPC). Сокет - це абстрактна кінцева точка з'єднання, через яку процес може відси­ лати або отримувати повідомлення. Обмін даними між двома процесами здій­ снюють через пару сокетів, по одному на кожен процес. Абстрактність сокету по­ лягає в тому, що він приховує особливості реалізації передавання повідомлень - після того як сокет створений, робота з ним не залежить від технології передаван­ ня даних, тому один і той самий код можна без великих змін використовувати для роботи із різними протоколами зв'язку. Особливості протоколу передавання даних і формування адреси сокету ви­ значає комунікаційний домен; його потрібно зазначати під час створення кожного сокету. Прикладами доменів можуть бути домен Інтернету (який задає протокол зв'язку на базі TCP/IP) і локальний домен або домен UNIX, що реалізує зв'язок із використанням імені файла (подібно до поіменованого каналу). Сокет можна ви­ користовувати у поєднанні тільки з одним комунікаційним доменом. Адреса со­ кету залежить від домену (наприклад, для сокетів домену UNIX такою адресою буде ім'я файла). Способи передавання даних через сокет визначаються його типом. У конкрет­ ному домені можуть Наприклад, і для домену Інтернет, і для домену UNIX підтримуються сокети та­ ких типів: + потокові (stream sockets) — задають надійний двобічний обмін даними суціль­ ним потоком без виділення меж (операція читання даних повертає стільки да­ них, скільки запитано або скільки було на цей момент передано); • дейтаграмні (datagram sockets) - задають ненадійний двобічний обмін пові­ домленнями із виділенням меж (операція читання даних повертає розмір того повідомлення, яке було відіслано). Під час обміну даними із використанням сокетів зазвичай застосовується техно­ логія клієнт-сервер, коли один процес (сервер) очікує з'єднання, а інший (клієнт) з'єднують із ним. Перед тим як почати працювати з сокетами, будь-який процес (і клієнт, і сер­ вер) має створити сокет за допомогою системного виклику socket ( ). Параметрами цього виклику задають комунікаційний домен і тип сокету. Цей виклик повертає дескриптор сокету — унікальне значення, за яким можна буде звертатися до цьо­ го сокету. Подальші дії відрізняються для сервера і клієнта. Спочатку розглянемо послі­ довність кроків, яку потрібно виконати для сервера.

  1. Сокет пов'язують з адресою за допомогою системного виклику bind( ). Для со­ кетів домену UNIX як адресу задають ім'я файла, для сокетів домену Інтерне-ту - необхідні характеристики мережного з'єднання. Далі клієнт для встанов­ лення з'єднання й обміну повідомленнями має буде вказати цю адресу.
  2. Сервер дає змогу клієнтам встановлювати з'єднання, виконавши системний виклик 1 і sten ( ) для дескриптора сокету, створеного раніше.
  3. Після виходу із системного виклику 1 і sten( ) сервер готовий приймати від клі­ єнтів запити на з'єднання. Ці запити вишиковуються в чергу. Для отримання запиту із цієї черги і створення з'єднання використовують системний виклик acceptO. Внаслідок його виконання в застосування повертають новий сокет для обміну даними із клієнтом. Старий сокет можна використовувати далі для приймання нових запитів на з'єднання. Якщо під час виклику accept ( ) запити на з'єднання в черзі відсутні, сервер переходить у стан очікування.

Для клієнта послідовність дій після створення сокету зовсім інша. Замість трьох кроків досить виконати один - встановити з'єднання із використанням системного виклику connecte). Параметрами цього виклику задають дескриптор створеного раніше сокету, а також адресу, подібну до вказаної на сервері для ви­ клику bind( ). Після встановлення з'єднання (і на клієнті, і на сервері) з'явиться можливість передавати і приймати дані з використанням цього з'єднання. Для передавання даних застосовують системний виклик send( ), а для приймання — recv( ). Зазначену послідовність кроків використовують для встановлення надійного з'єднання. Якщо все, що нам потрібно, - це відіслати і прийняти конкретне пові­ домлення фіксованої довжини, то з'єднання можна й не створювати зовсім. Для цього як відправник, так і одержувач повідомлення мають попередньо зв'язати сокети з адресами через виклик bindO. Потім можна скористатися викликами прямого передавання даних: sendtoO - для відправника і recvfromO — для одержувача. Параметрами цих викликів задають адреси одержувача і відправника, а також адреси буферів для даних. Докладніше використання сокетів буде описано в розділі 16. Віддалений виклик процедур Технологія віддаленого виклику процедур (Remote Procedure Call, RPC) [37, 50, 52, 57] є прикладом синхронного обміну повідомленнями із підтвердженням отримання. Розглянемо послідовність кроків, необхідних для обміну даними в цьому разі.

  1. Операцію send оформляють як виклик процедури із параметрами.
  2. Після виклику такої процедури відправник переходить у стан очікування, а да­ ні (ім'я процедури і параметри) доставляються одержувачеві. Одержувач мо­ же перебувати на тому самому комп'ютері, чи на віддаленій машині; техноло­ гія RPC приховує це. Класичний віддалений виклик процедур передбачає, що процес-одержувач створено внаслідок запиту.
  3. Одержувач виконує операцію receive і на підставі даних, що надійшли, вико­ нує відповідні дії (викликає локальну процедуру за іменем, передає їй пара­ метри і обчислює результат).
  4. Обчислений результат повертають відправникові як окреме повідомлення.
  5. Після отримання цього повідомлення відправник продовжує своє виконання, розглядаючи обчислений результат як наслідок виклику процедури. Приклади використання віддаленого виклику процедур будуть нами розгляну­

ті в розділі 20.

Висновки

  • Потоки різних процесів, що взаємодіють, мають використовувати засоби між-процесової взаємодії, завданнями якої є забезпечення обміну даними між за­ хищеними адресними просторами, а також їхня синхронізація. До основних видів міжпроцесової взаємодії належать передавання повідомлень, розподі-лювана і відображувана пам'ять.
  • Головною особливістю передавання повідомлень є те, що ця технологія не вимагає наявності спільно використовуваних даних. Процеси обмінюються повідомленнями змінної довжини за допомогою примітивів send і receive. Ця технологія може бути застосована для організації взаємодії між процеса­ ми, виконуваними на віддалених комп'ютерах.

Контрольні запитання та завдання

  1. Припустімо, що до комунікаційного каналу, наданого ОС, можуть «підклю­ чатися» два процеси. Які синхронізаційні примітиви на рівні ядра ОС можуть бути використані для обміну даними цим каналом відповідно до технології програмних каналів (pipes)? Як приклад ОС візьміть систему Linux.
  2. Перелічіть можливі відмінності реалізації черги повідомлень і програмного каналу на рівні ядра ОС.
  3. Система обміну повідомленнями надає примітиви send і receive. Примітив гесеі ve призупиняє процес, якщо немає повідомлень, призначених для нього. Чи можливе взаємне блокування процесів, якщо не враховувати інших пові­ домлень, а спільних даних у процесів немає?
  4. Реалізуйте систему обміну повідомленнями між потоками на базі стандартних синхронізаційних примітивів розділу 5. Операція int msg_send(int msg, int priority) передає в систему повідомлення із заданим пріоритетом. Операція int msg_recv(int priority) вилучає із системи найстаріше повідомлення з пріори­ тетом, більшим або рівним priority, і повертає його значення; якщо такого повідомлення немає, поточний потік призупиняють.
  5. Перелічіть спільні риси і відмінності поіменованих каналів і сокетів.