- •Національний авіаційний університет
- •Лабораторний практикум з дисципліни «Мультиплатформені операційні середовища»
- •Визначення, позначення і скорочення
- •2.2. Використання клавіатури пк в ос qnx
- •2.3. Основні команди в ос qnx
- •2.4. Робота в файловій системі ос qnx
- •2.5. Ініціювання і завершення роботи в графічній оболонці Photon
- •3. Зміст звіту про лабораторну роботу
- •4. Питання для самоконтролю
- •5. Завдання на лабораторну роботу
- •Лабораторна робота № 2. Компіляція програм Короткі теоретичні відомості
- •Мікроядро
- •Системні і користувацькі процеси
- •Драйвери пристроїв
- •Зв'язок між процесами (ipc)
- •Qnx як мережа
- •Текст програми
- •Лабораторна робота №4. Повідомлення Короткі теоретичні відомості Архітектура і структура обміну повідомленнями
- •Текст програми
- •Послідовність дій
- •Результати
- •Лабораторна робота № 5. Тайм-аути Короткі теоретичні відомості Тайм-аути ядра
- •Текст програми
- •Текст програми
- •Послідовність дій
- •Результати
- •Послідовність дій
- •Результати
- •Лабораторна робота № 8. Створення найпростішого сервера в ос qnx
- •Короткі теоретичні відомості Функція Socket
- •Функція Bind
- •Функції listen і accept
- •Читання з сокета
- •Запис в сокет
- •Закриття сокета
Лабораторна робота № 5. Тайм-аути Короткі теоретичні відомості Тайм-аути ядра
QNX/Neutrino дозволяє вам отримувати тайм-аути по всіх блокованим станам. Найбільш часто у вас може виникнути потреба в цьому при обміні повідомленнями: клієнт, посилаючи повідомлення серверу, не бажає чекати відповіді «вічно». У цьому випадку було б зручно використовувати тайм-аут ядра. Тайм-аути ядра також корисні в поєднанні з функцією pthreadjoin(): завершення потоку теж не завжди хочеться довго чекати.
Нижче наводиться декларація для функції TimerTimeout(), яка є системним викликом, відповідальним за формування тайм-аутів ядра.
#include <sys / neutrino.h>
int TimerTimeout (clockid_t id,
int flags,
const struct sigevent * notify,
const uint64_t * ntime,
uint64 t * otime);
Видно, що функція TimerTimeout() повертає ціле число (індикатор удачі/невдачі; 0 означає, що все гаразд, -1 - що сталася помилка, і її код записаний в errno). Джерело синхроимпульсів (CLOCK_REALTIME, тощо) вказується в id, параметр flags задає відповідний стан. Параметр notify завжди повинен бути подією повідомлення типу SIGEV_UNBLOCK; параметр ntime вказує відносний час, через який ядро повинно згенерувати тайм-аут. Параметр otime показує попереднє значення тайм-ауту і в більшості випадків не використовується (ви можете передати замість нього NULL).
Важливо відзначити, що тайм-аути "зводяться" функцією TimerTimeout(), а запускаються по входу в один зі станів, зазначених у параметрі flags. Скидається тайм-аут при поверненні; з будь-якого системного виклику. Це означає, що ви повинні заново «зводити» тайм-аут перед кожним системним викликом, до якого ви хочете його застосувати. Скидати тайм-аут після системного виклику не треба - це виконується автоматично.
Тайм-аути ядра і функція pthreadjoin()
Найпростіший приклад для розгляду - це використання тайм-ауту з функцією pthreadjoin().
Застосуємо макровизначення SIGEV_UNBLOCK_INIT() для ініціалізації структури події, але можна було встановити sigev_notify в SIGEV_UNBLOCK і «вручну». Можна було навіть зробити ще більш витончено, передавши NULL замість struct sigevent - функція TimerTimeout() розуміє це як знак, що потрібно використовувати SIGEV_UNBLOCK.
Якщо потік (заданий, в thread_id) залишається працюючим більше 10 секунд, то системний виклик завершиться по тайм-ауту - функція pthreadjoin() повернеться з помилкою, встановивши errno в ETIMEDOUT.
Ви можете використовувати й іншу «стенографію», вказавши NULL як значення тайм-ауту (параметр ntime в декларації вище), що накаже ядру не блокуватися в даному стані. Цей прийом можна використовувати для організації програмного опитування. (Хоч програмне опитування і вважається поганим тоном, його можна досить ефективно використовувати у випадку з pthreadjoin(), періодично перевіряючи, чи завершився потрібний потік. Якщо ні, можна поки зробити що-небудь інше.)
Нижче представлений приклад програми, в якій демонструється неблокуючий виклик pthreadJoin():
int
pthread_join_nb (int tid, void ** rval)
{
TimerTimeout (CLOCK_REALTIME, _NTO_TIMEOUT_JOIN, NULL, NULL, NULL);
return (pthread_join (tid, rval)); )
Тайм-аути ядра при обміні повідомленнями
Все стає трохи складніше, коли ви використовуєте тайм- аути ядра при обміні повідомленнями. На момент відправки клієнтом повідомлення сервер може як очікувати його, так і ні. Це означає, що клієнт може заблокуватися як з передачі (якщо сервер ще не прийняв повідомлення), так і по відповіді (якщо сервер прийняв повідомлення, але ще не відповів). Основний сенс тут у тому, що ви повинні передбачити обидва блокуючих стани в параметрі flafs функції TimerTimeout(), тому що клієнт може опинитися в будь-якому з них.
Щоб задати кілька станів, складіть їх операцією АБО (OR): TimerTimeout(_NTO_TIMEOUT_SEND | _NTO_TIMEOUT_REPLY).
Це викличе тайм-аут кожного разу, коли ядро переведе клієнта в стан блокування з передачі (SEND) або по відповіді (REPLY). В тайм-ауті SEND-блокування немає нічого особливого - сервер ще не прийняв повідомлення, значить, нічого для цього клієнта він не робить. Це значить, що якщо ядро генерує тайм-аут для SEND-блокованого клієнта, сервер про це інформувати не обов'язково. Функція MsgSend() клієнта поверне ознаку ETIMEDOUT і обробка тайм-ауту завершиться.
Однак, якщо сервер вже прийняв повідомлення клієнта, і клієнт бажає розблокуватися, для сервера існує два варіанти реакції. Якщо сервер не вказав прапорець _NTO_CHF_UNBLOCK на каналі, по якому було прийнято повідомлення, клієнт буде розблоковано негайно, і сервер не отримає про це ніякого оповіщення. У більшості серверів, прапорець _NTO_CHF_UNBLIOCK завжди встановлений. В цьому випадку ядро посилає серверу імпульс, а клієнт залишається заблокованим до тих пір, поки сервер йому не відповість! Це зроблено для того, щоб сервер міг дізнатися про запит клієнта на розблокування і виконати з цього приводу якісь дії.
