69762

Введення-виведення у режимі користувача

Лекция

Информатика, кибернетика и программирование

Тут зупинимося на взаємодії підсистеми введення-виведення із процесами режиму користувача та на різних методах організації введення-виведення з режиму користувача. Синхронне введення-виведення У більшості випадків введення-виведення на рівні апаратного...

Украинкский

2014-10-09

63 KB

0 чел.

Тема 10. Введення-виведення у режимі користувача

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

10.1. Синхронне введення-виведення

У більшості випадків введення-виведення на рівні апаратного забезпечення кероване перериваннями, а отже є асинхронним. Однак використати асинхронну обробку даних завжди складніше, ніж синхронну, тому найчастіше введення-виведення в ОС реалізоване у вигляді набору блокувальних або синхронних системних викликів, подібних до read(), write() або fcntl (). Під час виконання такого виклику поточний потік призупиняють, переміщуючи в чергу очікування для цього пристрою. Після завершення операції введення-виведення і отримання всіх даних від пристрою потік переходить у стан готовності та може продовжити своє виконання.

Однак синхронне введення-виведення підходить не для всіх застосувань. Зокрема, воно не підходить для таких категорій програм:

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

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

мультимедійних застосувань (відіславши запит на читання одного кадру, потрібно одночасно показувати інші).

Для вирішення цієї проблеми запропоновано кілька підходів, про які йтиметься нижче.

10.2. Багатопотокова організація введення-виведення

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

Такий підхід має багато переваг і може бути рекомендований для використання у багатьох видах застосувань. Наведемо приклад розробки багатопотокового сервера за принципом «потік для запиту» (thread per request).

У таких серверах є головний потік, який очікує безпосередніх запитів клієнта на отримання даних (виконуючи синхронну операцію read О або recvfromO для сокетів). Після отримання кожного запиту головний потік створює новий робочий потік для обробки його запиту, після чого продовжує очікувати подальших запитів. Робочий потік обробляє запит і завершується. Такий підхід застосовують для зв'язку без збереження стану, коли обробка одного запиту не залежить від обробки іншого. Ось псевдокод сервера, що працює за таким принципом:

void concurrent_server() {

 for (; ;) {

read (fd. &request); // синхронно очікувати запит

// створити потік для обробки запиту

create_thread (worker_thread. request):

}

}

// функція потоку обробки запиту

void worker_thread(request_t request) {

process_request(request); // обробити запит

}

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

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

♦ Не завжди варто додавати багатопотоковість в однопотокове застосування тільки тому, що в ньому знадобилося виконати асинхронне введення-виведення.

♦ Потрібно реалізовувати синхронізацію потоків.

  •  Може знизитися надійність застосування.
  •  Кваліфікація програмістів може виявитися недостатньою для реалізації багатопотоковості.

Усе це призводить до значного поширення технологій, альтернативних до цього підходу. Розглянемо їх.

10.3. Введення-виведення із повідомленням

Першою технологією, яку можна використати для організації введення-виведення без блокування і яка не вимагає організації багатопотоковості, є введення-виведення із повідомленням (notification-driven I/O) [77]. Ця технологія має й інші назви, наприклад мультиплексування введення-виведення (I/O multiplexing).

Загальні принципи введення-виведення із повідомленням

Якщо потрібно в циклі виконати блокувальний виклик (наприклад, readO) для кількох файлових дескрипторів, може трапитися так, що один із викликів заблокує поточний потік у той момент, коли на дескрипторі, який використовується в іншому виклику, з'являться дані. Доцільно організувати одночасне очікування отримання даних із кількох дескрипторів. Це і є основним мотивом розробки даної категорії засобів введення-виведення.

У цьому разі виконання введення-виведення поділяють на кілька етапів.

  1.   Спеціальний системний виклик (виклик повідомлення) визначає, чи можна виконати синхронне введення-виведення хоча б для одного дескриптора із заданого набору без блокування потоку. У POSIX визначено виклики повідомлення poll() і select().
  2.   Як тільки хоча б один дескриптор із набору стає готовий до введення-виведення без блокування, виклик повідомлення повертає керування; при цьому поточний потік може визначити, для яких саме дескрипторів може бути виконане введення-виведення або які з них змінили свій стан (тобто отримати повідомлення про стан дескрипторів).
  3.   Потік, що викликає, може тепер у циклі обійти всі дескриптори, визначені внаслідок повідомлення на етапі 2, і виконати введення-виведення для кожного з них, блокування поточного потоку ця операція в загальному випадку не спричинить.

Проілюструємо застосування цієї технології на прикладі реалізації реактивного сервера [54]. Такий сервер відповідає на запити клієнтів в одному потоці виконанням у циклі опитування стану набору дескрипторів, визначення тих із них, на які прийшли запити, та подальшого виконання цих запитів.

Введення-виведення із повідомленням про стан дескрипторів

Спочатку реалізуємо реактивний сервер на основі технології введення-виведення із повідомленням про стан дескрипторів (state-based notification). Це традиційний підхід, який використовується багато років. Необхідно виконати такі кроки.

  1.   Підготувати структуру даних (назвемо її fdarr) з описом усіх дескрипторів, стан яких потрібно відстежувати.
  2.   Передати fdarr у системний виклик повідомлення (у POSIX до таких викликів належать уже згадані select () і poll ()). Після виходу із виклику повідомлення fdarr міститиме інформацію про стан усіх відстежуваних дескрипторів (які з них готові до виконання введення-виведення без блокування, а які – ні).
  3.   Для дослідження результатів повідомлення обійти в циклі всі елементи fdarr і для кожного із них визначити готовність відповідного дескриптора; якщо він готовий – виконати для нього введення-виведення.

Ось псевдокод реактивного сервера із використанням повідомлення про стан дескрипторів:

void reactive_server () {

// цикл опитування набору дескрипторів fdarr. підготовленого раніше

for ( ; : ) {

select (&fdarr);        // прослуховування набору

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

for (і=0; і <= count(fdarr); i++) {

if ( requestjs_ready (fdarr[i]) ) { // якщо був запит

read (fdarr[i], &request); // одержати дані запиту

process_request (request); // обслужити клієнта

}

}

}

}

Незважаючи на те що такий сервер використовує всього один потік, продуктивність його роботи може бути високою, якщо запити обслуговують достатньо швидко. Сервер працює так:

select () повертає інформацію про ті запити, які потрібно обслужити;

усі ці запити обслуговують один за одним без затримок на введення-виведення; поки їх обслуговують, надходять нові;

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

Отже, запити потрапляють на обробку групами тим більшими, чим більше приходить запитів. Немає очікування ні під час виклику select(), ні під час читання даних із дескриптора. Усе це значно підвищує продуктивність.

Зазначимо, що в циклі обходу fdarr було обстежено готовність всіх його елементів до введення-виведення. Виникає запитання: чи завжди обов'язково проводити вичерпне обстеження, чи є можливість отримувати тільки інформацію про готові дескриптори? На жаль, для цього підходу такої можливості немає.

Основною особливістю введення-виведення із повідомленням про стан дескрипторів є те, що в разі його використання не зберігається стан. Кожен виклик повідомлення вимагає передавання всього набору дескрипторів і повертає «миттєвий знімок» стану цих дескрипторів. Це потребує повного обходу цього списку як всередині виклику повідомлення, так і в коді, що його викликав. Такий обхід може серйозно позначитися на продуктивності у разі великої кількості дескрипторів. Таким чином, інформація про неактивні дескриптори даремно копіюватиметься у ядро і назад під час кожного виклику повідомлення.

Введення-виведення із повідомленням про події

Для того щоб підвищити ефективність цієї схеми, запропоновано інший підхід -введення-виведення із повідомленням про події (event-based notification) [77].

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

Найвідомішими є приклади реалізації такого підходу для FreeBSD (kqueue) і для Linux 2.6 (epoll).

Виконання введення-виведення в цьому разі зводиться до таких кроків.

1. Спеціальний системний виклик (у Linux epol l_create()) створює структуру даних у ядрі; зазвичай як параметр у такий виклик передають максимальну кількість дескрипторів, які потрібно контролювати. Таку структуру даних на-зивають прослуховувальним об'єктом.

  1.   Після створення такого об'єкта для нього потрібно сформувати набір контрольованих дескрипторів, для кожного з них вказують події, які цікавлять потік, що виконував виклик. У Linux це робиться окремим викликом epoll_ctl(), один із можливих варіантів виконання якого додає дескриптор у набір.
  2.   Виклик повідомлення (у Linuxepoll_wait()) при цьому повертає інформацію тільки про ті дескриптори, які змінили стан із моменту останнього виклику (а не про всі дескриптори, як для select() або poll ()).

Ось псевдокод реактивного сервера із використанням повідомлення про події:

void reactive_server2 () {

epfd = epoll_create();   // створити прослуховувальний об'єкт

// додати дескриптори в прослуховувальний об'єкт

for (i=0; i<=count(fdarr);i++)

epoll_ctl(epfd. ADD.  fdarr[i]);

// цикл опитування набору дескрипторів у прослуховувальному об'єкті

for ( : ; ) {

epoll_wait (epfd. Sactive);    // визначення активного набору

// цикл обслуговування запитів

for (і=0; і <= count(active); i++) {

read (active[i]. &request): // одержати дані запиту

process_request (request);  // обслужити клієнта

}

}

}

Легко помітити, що внутрішній цикл спростився. Зазначимо також, що використання внутрішньої структури даних позбавляє необхідності обходу всіх дескрипторів усередині epoll_wait().

10.4. Асинхронне введення-виведення

Асинхронне введення-виведення реалізоване у деяких UNIX-системах (є стандарт POSIX для таких операцій). Одна з найповніших реалізацій цієї технології доступна також в системах лінії Windows ХР, де її називають введенням-виведен-ням із перекриттям (overlapped I/O). Основна ідея тут полягає в тому, що потік, який почав виконувати введення-виведення, не блокують до його завершення. Асинхронне введення-виведення зводиться до виконання таких дій.

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

Операція може бути перервана до свого завершення.

Основним підходом до отримання повідомлення про завершення асинхронного введення-виведення є виконання операції очікування завершення введення-виведення. При цьому потік призупиняють до завершення асинхронної операції.

Контрольні питання:

1. Синхронне введення-виведення.

2. Багатопотокова організація введення-виведення.

3. Загальні принципи введення-виведення із повідомленням.

4. Введення-виведення із повідомленням про стан дескрипторів.

5. Введення-виведення із повідомленням про події.

6. Асинхронне введення-виведення.


 

А также другие работы, которые могут Вас заинтересовать

32801. Условия формирования западноевропейской философии в Средние века. Роль христианства в развитии культуры 15.27 KB
  Условия формирования западноевропейской философии в Средние века. Этапы развития и характерные черты средневековой философии. В развитии философии Средних веков можно выделить несколько основных этапов: 1 апологетика II IV вв. В этот период не было создано философских систем но был намечен круг вопросов ставших центральными в средневековой философии: о Боге и соотношении Бога и мира о сотворении мира и структуре мироздания о сущности человека и его месте в мире; 2 патристика V IX вв.
32802. Философия Августина Аврелия (Блаженного). И Фомы Аквинского 14.95 KB
  Учение о Боге и мире. Бог рассматривается им как начало всего сущего как единственная причина возникновения вещей. Бог вечен и неизменен. Мир созданных богом вещей изменчив и пребывает во времени.
32803. Особенности философии Возрождения. Её связь с наукой и искусством. Учения о природе и познании 18.84 KB
  Особенности философии Возрождения. Эпоха Возрождения Ренессанса переходный период от Средних веков к Новому времени XV [в Италии с XIV] XVI вв. Возрождение художественноэстетическая эпоха провозгласившая что высшее призвание человека в мире быть творцом и созидателем Этапы развития и характерные черты философии Возрождения. В философии эпохи Возрождения можно выделить 3 этапа: гуманистический сер.
32804. Эмпиризм и сенсуализм в философии нового времени 16.32 KB
  Локк подчеркивает особую роль органов чувств в процессе познания.Бэкон сделал научное познание в центре его внимания вопросы о целях и методах научного познания.Однако он утверждает что на пути познания имеется множество заблуждений препятствующих получению достоверного знания. Бэкон выделяет 4 вида идолов познания: 1 идолы рода являются следствием ограниченности человеческого ума несовершенством органов чувств; 2 идолы пещеры обусловлены индивидуальными особенностями человека: каждый человек имеет свой внутренний субъективный мир...
32805. Рационализм в философии нового времени 17.35 KB
  Эти две субстанции пересекаются и активно взаимодействуют однако их взаимосвязь является лишь механической. В человеке материальная и духовная субстанции проявляются как тело и душа. В понятии единой субстанции т. Спиноза называет следующие свойства единой субстанции: независимое ни от чего существование; вечность; бесконечность; является внутренней причиной самой себя и всего сущего.
32806. Субъективный идеализм в философии Н.В. (Дж.Беркли, Д.Юм) 14.1 KB
  Джордж Беркли 1685 1753 гг. Беркли внес весомый вклад в теорию познания четко поставив вопрос о соотношении объективного и субъективного в ощущениях об объективности причинности и о видах существования. Беркли утверждал что мир не существует независимо от человека а представляет собой комплекс ощущений и восприятий. Философия Беркли основывается на следующих основных принципах: 1 существовать значит быть воспринимаемым; 2 я не в состоянии помыслить ощущаемые вещи или предмет независимо от их ощущения и восприятия; 3 мы никогда не...
32807. Философия французского Посвящения 17.75 KB
  Философия Просвещения опиралась на достижения наук: биологии физики медицины которые стали естественнонаучным основанием раскрытия сущности и природы человека. Просветители развивали материалистические взгляды на природу и человека. Дидро уподоблял человека инструменту наделенному чувствительностью и памятью а Ламетри проводил аналогию между человеком и машиной. Однако французские материалисты обращали внимание и на роль социальнокультурных факторов появления человека уделяли внимание роли языка как средства общения и познания мира.
32808. Особенности становления и основные черты немецкой классической философии 11.99 KB
  Немецкая философия конца ХVIII первой трети ХIХ веков представлена именами Канта Фихте Шеллинга Гегеля Фейербаха и представляет собой важный этап в развитии мировой философской мысли. Произведения Шиллера и Гете философские труды Канта и Гегеля отразили противоречивость эпохи. Маркс назвал философию Канта теорией буржуазной революции.
32809. Философия И. Канта: субъективный идеализм и агностицизм 14.27 KB
  Канта: субъективный идеализм и агностицизм. Основателем немецкой классической философии считается Иммануил Кант 1724 1804 гг. Основное содержание своей философии Кант изложил в виде следующих вопросов: Что я могу знатьЧто я должен делатьНа что я могу надеятьсяЧто есть человек. В творчестве Канта принято выделять 2 периода: 1 докритический до 70х гг.