Особливості багатозадачності в середовищі Windows
Контрольная работа - Компьютеры, программирование
Другие контрольные работы по предмету Компьютеры, программирование
»ягає в тім, що останню можна використовувати тільки в межах одного процесу (одного запущеного додатка), а семафорами, що виключають, можуть користатися різні процеси.
Semaphore глобальний обєкт синхронізації, що має лічильник для ресурсів, з ним повязаних. В достатньо грубому приближенні мютекс можна розглядати, як частковий випадок семафора з двома станами.
Іншими словами, критичні розділи - це локальні семафори, що доступні в рамках тільки однієї програми, а семафори, що виключають, можуть бути глобальними обєктами, що дозволяють синхронізувати роботу програм (тобто різні запущені додатки можуть розділяти ті самі дані).
Розглянемо основні функції семафора, що виключає, на прикладі роботи з обєктами mutex.
1. Створення обєкта mutex
HANDLE CreateMutex(
LPSECURITY_ATTRIBUTES lpMutexAttributes,
BOOL bInitialOwner,
LPCTSTR lpName)
lpMutexAttributes - покажчик на структуру SECURITY_ATTRIBUTES (у Windows 95 даний параметр ігнорується);
bInitialOwner - указує первісний стан створеного обєкта (TRUE - обєкт відразу стає зайнятим, FALSE - обєкт вільний);
lpName - указує на рядок, що містить імя обєкта. Імя необхідне для доступу до обєкта інших процесів, у цьому випадку обєкт стає глобальним і їм можуть оперувати різні програми. Якщо вам не потрібний іменований обєкт, то вкажіть NULL. Функція повертає покажчик на обєкт mutex. Надалі цей покажчик використовується для керування семафором, що виключає.
2. Закриття (знищення) обєкта mutex
BOOL CloseHandle(HANDLE hObject)
3. Універсальна функція запиту доступу
DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds) - універсальна функція, призначена для запиту доступу до синхронізуючого обєкту (у даному випадку до обєкта mutex).
hHandle - покажчик на синхронізуючий обєкт (у даному випадку передається значення, повернуте функцією CreateMutex);
dwMilliseconds - час (у міллісекундах), протягом якого відбувається чекання звільнення обєкта mutex. Якщо передати значення INFINITE (нескінченність), то функція буде чекати нескінченно довго.
Дана функція може повертати наступні значення:
WAIT_OBJECT_0 - обєкт звільнився;
WAIT_TIMEOUT - час чекання звільнення пройшов, а обєкт не звільнився;
WAIT_ABANDON - відбулося відмовлення від обєкта (тобто процес, що володіє даним обєктом, завершилося, не звільнивши обєкт). У цьому випадку система (а не "процес-власник") переводить обєкт у вільний стан. Таке звільнення обєкта не припускає гарантій у захищеності даних;
WAIT_FAILED - відбулася помилка.
4. Звільнення обєкта mutex
BOOL ReleaseMutex(HANDLE hMutex) - звільняє обєкт mutex, переводячи його з зайнятого у вільний стан.
Чи дійде черга до вас?
Отже, якщо програмі необхідно ввійти в поділюваний код, то вона запитує дозвіл шляхом виклику функції WaitForSingleObject. При цьому якщо обєкт синхронізації зайнятий, то виконання запитуючого потоку припиняється і невикористана частина відведеного часу передається іншому потоку. А тепер увага! Теоретично: як тільки обєкт стає вільним, що очікує потік відразу захоплює його. Але це тільки теоретично. На практиці цього не відбувається. Захоплення обєкта, що звільнився, відбувається лише тоді, що коли очікує потік знову одержить свій квант часу. І тільки тоді він зможе перевірити, чи звільнився обєкт, і, якщо так, захопити його.
Непрямим підтвердженням вищевикладених міркувань може служити той факт, що Microsoft не передбачила підтримку черговості запитів на доступ до обєкта синхронізації. Тобто якщо кілька процесів очікують звільнення того самого обєкта синхронізації, то немає ніякої можливості довідатися, який саме з них першим одержить доступ до обєкта, що звільнився.
Пояснимо це на наступному прикладі. Нехай, трьом потокам необхідно звернутися до однієї ділянки коду, причому одноразово ця ділянка повинна виконувати тільки один потік. Введемо обєкт синхронізації mutex, що регулює доступ потоків до цієї ділянки коду. Коли потік 1 захопив обєкт mutex і став виконувати поділювану ділянку коду, потік 2 запросив дозвіл на доступ (тобто викликав функцію WaitForSingleObject), а система перевела потік 2 у режим чекання. Через якийсь час потік 3 теж запросив дозвіл на вхід у цей код і теж перейшов у режим чекання. Тепер, якщо потік 1 звільнить обєкт синхронізації, те невідомо, який потік (2 чи 3) його захопить, - усі залежить від того, хто з них першим одержить свій квант часу для продовження роботи. Нехай обєктом синхронізації заволодів потік 3, а поки він виконував поділюваний розділ, потік 1 знову запросив доступ до обєкта синхронізації - і знову стало два конкуруючих потоки (1 і 2). І хто з них першим "достукається" до ділянки коду, що виконується, невідомо: може случитися так, що потік 2 ніколи не буде допущений до бажаної ділянки коду і надовго залишиться в стані чекання... А як відомо, гірше немає чекати, хоча потоку це байдуже. Інша справа - вам...
Події
Подія - це обєкт синхронізації, стан якого може бути установлений сигнальним шляхом виклику функцій SetEvent або PulseEvent. Існує два типа подій:
Тип обєкту Опис Подія з ручним “сбросом”Це обєкт, сигнальний стан якого зберігається до ручного” сброса” функцією ResetEvent. Як тільки стан обєкту установлений в сигнальний, всі потоки, що знаходяться в циклі очікування цього обєкту, продовжують своє виконання (звільняються).Подія з автоматичним “сбросом”Обєкт, сигнальний стан якого зберігається до тих пір, поки не буде звільнений єдиний потік, після чого система автоматично установлює несигнальний стан події. Якщо нема по