Читайте также: |
|
Алгоритм багаторівневих черг зі зворотним зв'язком (multilevel feedback queues)
є найуніверсальнішим алгоритмом планування (за допомогою налаштування параметрів його можна звести майже до будь-якого іншого алгоритму), але при цьому
одним із найскладніших у реалізації.
З погляду організації структур даних цей алгоритм схожий на звичайний алгоритм багаторівневих черг: є кілька черг готових потоків із різним пріоритетом,
при цьому потоки черги із нижчим пріоритетом виконуються, тільки коли всі
черги верхнього рівня порожні.
Відмінності між двома алгоритмами полягають у тому, що:
♦ потокам дозволено переходити з рівня на рівень (із черги в чергу);
♦ потоки в одній черзі об'єднуються не за пріоритетом, а за довжиною інтервалу
використання процесора, потоки із коротшим інтервалом перебувають у черзі
з більшим пріоритетом.
4.4.6. Усередині всіх черг, крім найнижчої, використовують кругове планування
(у найнижчій працює FIFO-алгоритм). Різні черги відповідають різній довжині
кванта часу — що вищий пріоритет, то коротший квант (звичайно довжина кванта для сусідніх черг зменшується удвічі). Якщо потік вичерпав свій квант часу,
він переміщається у хвіст черги із нижчим пріоритетом (і з довшим квантом).
У результаті потоки з коротшими інтервалами (наприклад, обмежені введенням-
виведенням) залишаються з високим пріоритетом, а потоки з довшими інтервалами подовжують свій квант часу (рис. 4.4). Можна також автоматично переміщати потоки, які давно не отримували керування, із черги нижнього рівня на
рівень вище.
Лотерейне планування
Лотерейне планування (lottery scheduling) — це останній алгоритм, який ми розглянемо. Він простий для розуміння і легкий у реалізації, разом з тим має великі
можливості.
Ідея лотерейного планування полягає у тому, що:
♦ потік отримує деяку кількість лотерейних квитків, кожен з яких дає право користуватися процесором упродовж часу Т;
♦ планувальник через проміжок часу Т вибирає випадково один лотерейний
квиток;
♦ потік, «що виграв», дістає керування до наступного розіграшу.
Лотерейне планування дає змогу:
♦ емулювати кругове планування, видавши кожному потокові однакову кількість квитків;
♦ емулювати планування із пріоритетами, розподіляючи квитки відповідно до
пріоритетів потоків;
♦ емулювати SRTCF - давати коротким потокам більше квитків, ніж довгим
(якщо потік отримав хоча б один квиток, він не голодуватиме);
♦ забезпечити розподіл процесорного часу між потоками — дати кожному потокові кількість квитків, пропорційну до частки процесорного часу, який потрібно йому виділити (наприклад, якщо є три потоки, і треба, щоб потік А займав 50 % процесора, а потоки В і С — по 25 %, можна дати потоку А два
квитки, а потокам В і С — по одному);
♦ динамічно міняти пріоритети, відбираючи і додаючи квитки по ходу.
Хоча більшість цих задач може бути розв’язана лотерейним плануванням лише
приблизно, з деякою ймовірністю, на практиці отримують цілком задовільні результати. При цьому що довше працює система, то ближчими будуть результати до теоретичних значень (за законом великих чисел). Насправді лотерейне планування
використовує той факт, що вся ідеологія планування значною мірою є евристичною, оскільки не можна точно передбачити характер поведінки потоків у системі.
4.5. Реалізація планування в Linux
У цьому розділі розглянемо два варіанти реалізації планування в Linux — традиційну (належить до ядер версій до 2.4 включно) і нову, включену в ядро версії 2.6.
Ядро Linux при плануванні не розрізняє процеси і потоки, тому для визначе-
ності ми надалі говоритимемо про планування процесів.
Усі процеси в системі можна поділити на три групи: реального часу із плануванням за принципом FIFO, реального часу із круговим плануванням, звичайні.
Планування процесів реального часу в ядрі
Стосовно процесів реального часу, достатньо сказати, що:
♦ вони завжди матимуть під час планування пріоритет перед звичайними процесами;
♦ процес із плануванням за принципом FIFO виконують доти, поки він сам не
віддасть процесор (наприклад, внаслідок призупинення або завершення) або
поки не буде витиснений процесом реального часу із вищим пріоритетом;
♦ те саме стосується процесу із круговим плануванням, крім того, що він додатково буде витіснений після вичерпання кванта часу.
Розглянемо алгоритм планування звичайних процесів [62]. В основі алгоритму
лежить розподіл процесорного часу на епохи (epochs). Упродовж епохи кожен
процес має квант часу, довжину якого розраховують у момент початку епохи.
Здебільшого різні процеси мають кванти різної довжини. Коли процес вичерпав
свій квант, його витісняють і протягом поточної епохи він більше не виконуватиметься. Керування передають іншому процесові. Якщо ж процес був призупинений для виконання введення-виведення або внаслідок синхронізації, його квант не вважають вичерпаним і він може бути вибраний планувальником упродовж
поточної епохи. Епоха закінчується, коли всі готові до виконання процеси вичерпали свої кванти. У цьому разі алгоритм планування перераховує кванти для всіх
процесів і розпочинає нову епоху.
Квант, який задають на початку епохи, називають базовим квантом часу процесу. Його значення можуть динамічно змінюватися системними викликами nice () і setpriority (). Процес-нащадок завжди успадковує базовий квант свого предка.
Пріоритет процесу буває двох видів: фіксований, для процесів реального часу,
що задають тільки під час створення процесу, та динамічний, для звичайних процесів, який залежить від базового пріоритету і часу, що залишився до вичерпання
кванта. Динамічний пріоритет будь-якого звичайного процесу завжди нижчий за
будь-який пріоритет процесу реального часу.
Опишемо найважливіші поля структури даних процесу стосовно планування:
¨ policy — визначає, до якої групи відноситься процес (звичайні, реального часу
з алгоритмом FIFO тощо);
¨ nice — задає величину, на якій ґрунтується базовий квант часу процесу (надалі для спрощення вважатимемо nice рівним базовому кванту, насправді це не
зовсім так);
¨ counter — містить кількість переривань таймера, що залишилися до вичерпання кванта часу процесу. На початку епохи counter надають значення базового
кванта і зменшують його на одиницю в обробнику переривання таймера.
Умови виклику процедури планування
Розглянемо ситуації, коли відбувається виклик процедури планування (її називають schedule ()).
¨ Коли процес повинен бути заблокований через те, що потрібний йому ресурс
у цей час недоступний. У цьому разі його керуючий блок спочатку додають
у відповідну чергу очікування, а потім відбувається перепланування.
¨ За допомогою відкладеного запуску (lazy invocation). Відкладений запуск полягає в тому, що у певний момент часу спеціальному полю need_resched структури
процесу надають значення 1. Це відбувається в таких випадках: коли поточний
процес вичерпав свій квант; коли у стан готовності переходить процес, пріоритет якого вищий, ніж у поточного; коли процес явно поступається своїм правом
виконання через відповідний системний виклик. При цьому негайного перепланування не відбувається, але пізніше, коли цей процес повинен знову отримати керування після переривання, він перевіряє, чи не дорівнює поле need_resched одиниці. Якщо рівність виконується, запускають процедуру планування.
Процедура планування
Ця процедура спочатку перевіряє, чи не переходить поточний процес у стан очікування, і якщо це так, вилучає його з черги готових процесів. Потім вибирається
процес для виконання. Для цього проглядають чергу готових процесів, для кожного процесу оцінюють динамічний пріоритет і вибирають процес із максимальним
його значенням. Алгоритм оцінки цього пріоритету описаний нижче. Для процесу, що вичерпав свій квант часу, він дорівнюватиме нулю.
Якщо жоден процес не був вибраний, поточний процес продовжує виконуватися. Коли ж вибір відбувся, контекст перемикають на новий процес.
Початок нової епохи
Особлива ситуація виникає тоді, коли для всіх процесів у черзі готових процесів
значення динамічного пріоритету дорівнює нулю, тобто всі вони вичерпали свій
квант і настав час починати нову епоху. Проте це не означає, що система взагалі
не має процесів, для яких квант не вичерпаний, — вони можуть перебувати в чергах очікування (найчастіше це процеси, обмежені введенням-виведенням).
Коли розпочинається нова епоха, відбувається перерахування квантів для всіх
процесів системи (не тільки для процесів у стані готовності). При цьому довжину
кванта для кожного процесу задають рівною сумі його базового пріоритету і половини частини кванта, що залишилася в нього:
for_each_task (р)
p.counter = (p.counter / 2) + р.nісе;
Оскільки до початку нової епохи ненульовий квант залишається тільки у процесів, які не перебувають у стані готовності, цей алгоритм надає певну перевагу
процесам, обмеженим можливостями введення-виведення. При цьому значення
кванта для процесу ніколи не зможе стати більшим, ніж подвоєне значення його
базового пріоритету.
Розрахунок динамічного пріоритету
Тепер повернемося до обчислення динамічного пріоритету процесу. Для цього
використовують функцію goodness (). Розглянемо можливі значення, які вона може повернути.
♦ 0 — у разі, коли процес вичерпав свій квант часу. Цей процес не буде вибраний для виконання, крім випадку, коли він стоїть у черзі готових процесів
першим, а всі інші процеси черги також вичерпали свій квант.
♦ Від 0 до 1000 — у разі, коли процес не вичерпав свого кванту часу. Це значення розраховують на основі значення базового кванта процесу й частини поточного кванта, що залишилася в нього. Спрощено це можна зобразити так:
с = p.counter + р.nісе:
де р — покажчик на керуючий блок процесу.
Звідси випливає, що більше часу залишилося процесу для виконання і що
довший його базовий квант, то вищий його пріоритет. Крім того, це значення додатково збільшують на одиницю для процесів, які використовують ту саму пам’ять, що й предки (наприклад, якщо процес відображає потік, створений за допомогою функції clone ()).
Перерахування кванта під час створення нового процесу
Тепер розглянемо, що відбувається під час створення нового процесу. Найпростіше рішення (копіювати значення counter у структуру даних нащадка) може призвести до того, що процеси будуть штучно подовжувати свій квант створенням
нових нащадків, виконуючих той самий код. Для того щоб цьому перешкодити,
після функції fork () значення counter розділяють навпіл: одна половина переходить нащадкові, інша залишається предкові.
Перелічимо недоліки алгоритму.
♦ Вибір процесу для виконання відбувається внаслідок розрахунку динамічного пріоритету для всіх процесів у черзі готових процесів. Зі збільшенням кількості готових процесів у системі переглядати цю чергу від початку до кінця
під час кожного виклику процедури планування стає невигідно.
♦ Якщо кількість процесів буде дуже великою, перерахування всіх динамічних
пріоритетів на початку нової епохи може виконуватися досить довго. З іншого боку, епохи змінюються рідше, що більше в системі процесів.
♦ Алгоритм розрахований на зменшення часу відгуку для процесів, обмежених
можливостями введення-виведення, навіть якщо вони не є інтерактивними
(наприклад, фоновий процес індексації пошукової системи) і не потребують
малого часу відгуку.
♦ Зі збільшенням кількості процесорів підтримувати загальні черги, які не враховують наявність різних процесорів, стає невигідно.
4.5.3. Сучасні підходи до реалізації планування
Зазначені недоліки починали істотно впливати на роботу системи, коли вона
функціонувала за умов граничного навантаження. У звичайних умовах традицій-
не планування в Linux працювало досить ефективно.
Проте робота над виправленням недоліків тривала. Як наслідок, у ядро версії 2.6 була інтегрована нова реалізація алгоритму планування [97]. Розглянемо
коротко, як вона допомагає розв’язувати названі раніше проблеми.
Насамперед, цей алгоритм підтримує окремі черги готових процесів для кожного процесора, забезпечуючи ефективну роботу за умов багатопроцесорності.
Ще одна проблема, яку має розв’язати новий алгоритм, пов'язана з необхідністю розраховувати у старому алгоритмі динамічний пріоритет для всіх готових
процесів під час кожного виклику процедури планування. Рішення приймають
таке: кожна черга готових процесів — це масив черг готових процесів, де елементи
упорядковані за динамічним пріоритетом. У результаті під час вибору процесу
для виконання достатньо продивитись чергу з найвищим пріоритетом до першого процесу, який можна запустити. Ця процедура не залежить від загальної кількості готових процесів у системі.
Є два масиви черг готових процесів — масив черг активних процесів і масив
черг процесів з вичерпаним квантом. Після того як процес вичерпав свій квант,
його переносять із першого масиву в другий. Коли в масиві активних черг не залишається жодного процесу, обидва масиви міняються місцями, і послідовність
кроків повторюють із самого початку. У підсумку з вичерпанням квантів процесами підвищується ймовірність запуску тих процесів, які до цього часу ще не
одержували керування.
У цьому розділі розглянемо системні виклики Linux, за допомогою яких можна
працювати із базовим пріоритетом процесів (величиною nice) і цим впливати на
їхнє планування.
Для зміни базового пріоритету процесу використовують виклик setpriority ():
#іnсlude <sys/resource.h>
int setpriority(int which, int who, int priority);
Зокрема, параметр which може набувати значення PRIO_PROCESS або PRIO_USER,
відповідно показуючи, що параметр who буде інтерпретований як ідентифікатор
процесу чи ідентифікатор користувача. У першому випадку задають пріоритет
для конкретного процесу (або для поточного процесу, якщо who дорівнює нулю),
у другому — для всіх процесів цього користувача.
Параметр priority задає новий пріоритет. Пріоритет може варіюватися в межах від -20 до 20, менші значення свідчать про вищий пріоритет. Значенням за
замовчуванням є 0. Негативні значення priority можуть задавати лише користувачі з правами адміністратора.
Для отримання інформації про поточний базовий пріоритет використовують
виклик getpriority():
int getpriority (int which, int who);
Цей виклик повертає значення пріоритету, параметри whichі who для нього мають той самий зміст, що й для функції setpriority ().
Розглянемо приклад використання цих викликів:
// задати пріоритет для поточного процесу
setprіогіty(PRI0_PR0CESS, 0, 10):
// довідатися про поточне значення пріоритету
printf ("поточний пріоритет: *d\n", getpriогіty(PRI0_PR0CESS. 0)):
Для відносної зміни базового пріоритету поточного процесу можна також використати системний виклик niсе ():
#іnсlude <unistd.h>
int nice (int inc); // змінює пріоритет поточного процесу на іnс
4.6. Реалізація планування у Windows ХР
Планування потоків у ядрі
Ядро Windows ХР розв'язує під час планування дві основні задачі [14, 97]:
♦ облік відносних пріоритетів, присвоєних кожному потокові;
♦ мінімізацію часу відгуку інтерактивних застосувань.
Базовою одиницею планування є потік. Під час планування ядро не розрізняє
потоки різних процесів, воно має справу з пріоритетами потоків, готових до виконання в певний момент часу.
Під час планування ядро працює з мінімальними версіями потоків (блоками
KTHREAD). У них зберігається така інформація, як загальний час виконання потоку, його базовий і поточний пріоритет, диспетчерський стан потоку (готовність, очікування, виконання тощо).
Пріоритети потоків і процесів
Для визначення порядку виконання потоків диспетчер ядра використовує систему пріоритетів. Кожному потокові присвоюють пріоритет, заданий числом у діапазоні від 1 до 31 (що більше число, то вище пріоритет). Пріоритети реального
часу — 16 - 31; їх резервує система для дій, час виконання яких є критичним чинником. Динамічні пріоритети - 1-15; вони можуть бути присвоєні потокам застосувань користувача.
Ядро системи може надати потоку будь-який динамічний пріоритет. Win32
АРІ не дає можливості зробити це з цілковитою точністю, у ньому використовують дворівневу систему, яка зачіпає як процес, так і його потоки: спочатку процесу присвоюють клас пріоритету, а потім потокам цього процесу - відносний
пріоритет, який відраховують від класу пріоритету процесу (називаного ще базовим пріоритетом). Під час виконання відносний пріоритет може змінюватися.
Розрізняють такі класи пріоритету процесів: реального часу (real-time, приблизно відповідає пріоритету потоку 24); високий (high, 13); нормальний (normal, 8);
невикористовуваний (idle, 4).
Відносні пріоритети потоку бувають такі: найвищий (+2 до базового); вище за
нормальний (+1 до базового); нормальний (дорівнює базовому); нижче за нормальний (-1 від базового); найнижчий (-2 від базового).
Є два додаткових модифікатори відносного пріоритету: критичний за часом
(time-critical) і невикористовуваний (idle). Перший модифікатор тимчасово задає для потоку пріоритет 15 (найвищий динамічний пріоритет), другий аналогічним чином задає пріоритет 1.
Особливості задання кванта часу
Важливою характеристикою системи є довжина кванта часу. Розрізняють короткі
й довгі кванти, для яких можна задати змінну та фіксовану довжину.
У Windows ХР інтерактивно можна задавати таку довжину кванта (вибирають Settings (Параметрьі) у групі Performance (Бьісгродействие) на вкладці Advanced
(Дополнительно) вікна властивостей My Computer (Свойсгва системьі)):
♦ короткі кванти змінної довжини (вкладка Advanced (Дополнительно), перемикач Programs (Програми) у групі властивостей Processor Scheduling (Распределение времени процесора)). Можлива довжина кванта - 10 або З0 мс, при цьому
застосування, з яким починає працювати користувач, автоматично переходить
до використання довших квантів. Ця установка надає перевагу інтерактивним
процесам;
♦ довгі кванти фіксованої довжини (вкладка Advanced (Дополнительно), перемикач Background services (Служб, работающих в фоновом режиме) у групі властивостей Processor Scheduling (Распределение времени процесора)). Довжина кванта
фіксована й дорівнює 120 мс. Ця установка надає перевагу фоновим процесам.
Пошук потоку для виконання
Для виконання новий потік вибирається, коли:
♦ минув квант часу для потоку (з використанням алгоритму пошуку готового
потоку);
♦ потік перейшов у стан очікування події (потік сам віддає квант часу і дає команду планувальникові запустити алгоритм пошуку готового потоку);
♦ потік перейшов у стан готовності до виконання (використовують алгоритм
розміщення готового потоку).
Планувальник підтримує спеціальну структуру даних — список готових потоків (dispatcher ready list). У цьому списку зберігається 31 елемент — по одному
для кожного рівня пріоритету. З кожним елементом пов'язана черга готових потоків, всі потоки з однаковим пріоритетом перебувають у черзі, яка відповідає їхньому рівню пріоритету.
Під час виконання алгоритму пошуку готового потоку планувальник переглядає всі черги потоків, починаючи з черги найвищого пріоритету (31). Як тільки
під час цього перегляду трапляється потік, його відразу вибирають для виконання.
За допомогою цього алгоритму вибирають перший потік непустої черги з найвищим пріоритетом. Можна сказати, що в межах однієї черги використовують алгоритм кругового планування, якщо не враховувати динамічну корекцію пріоритетів, яку ми розглянемо далі.
Алгоритм розміщення готового потоку поміщає потік у список готових потоків. Спочатку перевіряють, чи не володіє потік вищим пріоритетом, ніж той,
котрий виконується в цей момент. При цьому новий потік негайно починає виконуватися, а поточний поміщається у список готових потоків; у противному разі
новий потік поміщається в чергу списку готових потоків, відповідну до його пріоритету. У початку кожної черги розташовані потоки, які були витиснені до того, як вони виконувалися впродовж хоча б одного кванта, всі інші потоки поміщаються
в кінець черги.
Якщо подивитися на ситуацію з боку потоку, що виконується, то важливо
знати, коли він може бути витиснений. Це трапляється коли:
♦ потік перейшов у стан очікування;
♦ минув квант часу потоку;
♦ потік із вищим пріоритетом перейшов у стан готовності до виконання;
♦ змінився пріоритет потоку або пріоритет іншого потоку.
Динамічна зміна пріоритету і кванта часу
Під час виконання потоків динамічний пріоритет і довжина кванта часу можуть
бути скориговані ядром системи. Розрізняють два види такої динамічної зміни:
підтримка (boosting) і ослаблення (decay).
Підтримка зводиться зазвичай до тимчасового підвищення пріоритету потоків. Коли потік переходить у стан готовності до виконання внаслідок настання
події, на яку він очікував, виконують операцію підтримки.
♦ Під час завершення операції введення-виведення підвищення пріоритету
залежить від типу операції. Наприклад, після виконання дискових операцій
пріоритет збільшують на одиницю, після введення із клавіатури або обробки
події від миші — на 6.
♦ Під час зміни стану синхронізаційного об'єкта (докладніше такі об'єкти будуть розглянуті пізніше) пріоритет потоку, який очікує цієї зміни, збільшують
на одиницю.
♦ Вихід з будь-якого стану очікування для потоків інтерактивних застосувань
призводить до підвищення пріоритету на 2, таке саме підвищення відбувається під час переходу в стан готовності потоків, пов’язаних із відображенням інтерфейсу користувача.
♦ Для запобігання голодуванню потоки, які не виконувалися упродовж досить
тривалого часу, різко підвищують свій пріоритет (цей випадок розглянемо
окремо).
Зазначимо, що внаслідок операцій підтримки динамічний пріоритет потоку
не може перевищити значення 15 (максимально допустимого динамічного пріоритету). Якщо операція підтримки вимагає підвищення пріоритету до величини,
вищої за це значення, пріоритет збільшують тільки до 15.
Підвищення пріоритету внаслідок підтримки дедалі слабшає. Після закінчення кожного кванта часу поточний пріоритет потоку зменшують на одиницю, поки
він не дійде до базового, після чого пріоритет залишають на одному рівні до наступної операції підтримки.
Ще одним видом підтримки є зміна кванта часу для інтерактивних застосувань. Якщо під час налаштування системи задано використання квантів змінної
довжини, можна вказати, що для інтерактивних застосувань довжина кванта буде збільшуватися (це називають підтримкою кванта для інтерактивних застосувань). Якщо така підтримка задана, то коли інтерактивне застосування захоплює
фокус, всі його потоки отримують квант часу, який дорівнює значенню підтримки (дозволене одне з можливих значень кванта, наприклад, 40 або 60 мс).
З іншого боку, значення кванта може й зменшуватися (слабшати). Так, під час
виконання будь-якої функції очікування довжина кванта зменшується на одиницю.
Для потоків із пріоритетом реального часу динамічна зміна пріоритету або
довжини кванта ніколи не відбувається. Єдиний спосіб змінити пріоритет таких
потоків — викликати відповідну функцію із прикладної програми.
Запобігання голодуванню
Якщо в системі постійно є потоки з високим пріоритетом, може виникати голодування потоків, пріоритет яких нижчий. Для того щоб уникнути голодування, спеціальний потік ядра один раз за секунду обходить чергу готових потоків у пошуках тих, які перебували у стані готовності досить довго (понад 3 с) і жодного разу не отримали шансу на виконання. Коли такий потік знайдено, то йому присвоюють пріоритет 15 (і він дістає змогу негайного виконання); крім того, довжину його кванта часу подвоюють. Після того, як два кванти часу минають, пріоритет потоку і його квант повертаються до вихідних значень.
Цей алгоритм не враховує причин голодування і не розрізняє потоків інтерактивних і фонових процесів.
4.6.2. Програмний інтерфейс планування
У цьому розділі розглянемо функції Win32 АРІ, за допомогою яких можна працювати із класами пріоритетів процесів і відносних пріоритетів потоків [31].
Для зміни класу пріоритету процесу використовують функцію SetPriorityClass (), для визначення поточного класу пріоритету - функцію GetPriorityClass ():
BOOL SetPriorityClass(HANDLE ph, DWORD pclass);
DWORD GetPriorityCIass(HANDE ph);
Параметр ph визначає дескриптор процесу, для якого задають клас пріоритету, а параметр pclass — клас пріоритету. Можливі такі значення pclass:
♦ REALTIМЕ_РRIORITY_CLASS (реального часу);
♦ HIGH_PRIORITY_CLASS (високий);
♦ NORMAL_PRIORITY_CLASS (нормальний);
♦ IDLE_PRIORITY_CLASS (невикористовуваний).
Розглянемо приклад використання цих функцій:
HANDLE curh = GetCurrentProcess();
// задати клас пріоритету для поточного промесу
SetPriorityClass(curh, IDLE_PRIORITY_CLASS):
// взнати поточне значення класу пріоритету
printf("Поточний клас пріоритету: %d\n", GetPriorityClass(curh));
Щоб задати відносний пріоритет потоку, використовують функцію SetThreadPriority (), а щоб задати його значення — GetThreadPriority ().
BOOL SetThreadPriority (HANDLE th, int priority):
int GetThreadPriority (HANDLE th):
Параметр th є дескриптором потоку, параметр priority (і повернуте GetThreadPriority ()) може набувати одного з таких значень:
♦ THREAD_PRI0RITY_TIME_CRITICAL (критичний за часом);
♦ THREAD_PRIORITY_HIGHEST (найвищий);
♦ THREAD_PRIORITY_ABOVE_NORMAL (вищий за нормальний);
♦ THREAD_PRIORITY_NORMAL (нормальний);
♦ THREAD_RIORITY_BELOW_NORMAL (нижчий за нормальний);
♦ THREAD_PRIORITY_LOWEST (найнижчий);
♦ THREAD_PRIORITY_IDLE (невикористовуваний).
Розглянемо приклад використання цих функцій.
DWORD tid:
// створення потоку
HANDLE th = _beginthreadex(... CREATE_SUSPENDED, &tid);
// задання пріоритету
SetThreadPriority(th, THREAD_PRIORITY_IDLE);
// поновлення виконання потоку
ResumeThread(th);
// визначення пріоритету
printf("Поточний пріоритет потоку: %d\n". GetThreadPriority(th)):
// закриття дескриптора потоку
CloseHandle(th):
У даному прикладі ми створюємо потік у призупиненому стані, задаємо його
пріоритет, а потім поновлюємо його виконання. Для цього використана функція
ResumeThread(), що параметром приймає дескриптор потоку.
Висновки
♦ Задача планування потоків зводиться до організації виконання кількох потоків на одному процесорі так, аби у користувачів виникало враження, що вони
виконуються одночасно. Цілями планування є: мінімізація часу відгуку, максимізація пропускної здатності та справедливість. До основних стратегій планування належать витісняльна й невитісняльна багатозадачність. У сучасних
ОС застосовують витісняльну багатозадачність, коли рішення про перемикання контексту потоку приймають у коді ядра системи, а не в коді потоку.
♦ Розрізняють довготермінове, середньотермінове й короткотермінове планування. Найважливіший тут короткотерміновий планувальник, котрий використовують для прийняття рішення про те, який потік запустити на виконання в певний момент. До основних алгоритмів короткотермінового планування
належать планування кругове і з пріоритетами.
Контрольні запитання та завдання
1.Процес виконується в нескінченному циклі. За допомогою якого апаратного
пристрою операційна система може перехопити керування в цього процесу?
Опишіть особливості використання такого пристрою.
2.Наведіть приклади програм, під час виконання яких не буде жодних проблем
в ОС із витісняльною багатозадачністю, але виникнуть блокування системи в ОС із невитісняльною багатозадачністю.
3.
В комірках табл. 4.2 відобразіть, який із потоків буде займати процесор у фіксований момент часу в разі використання алгоритмів планування FIFO, RR (кругового), STCF, SRTCF і PS (з пріоритетами). |
Таблиця 4.1. | Параметри послідовності потоків | ||
Потік | Тривалість | Час надходження | Пріоритет |
Таблиця 4.2. Завантаження процесора для різних алгоритмів планування |
Час | FIFO | RR | STCF | SRTCF | PS |
... |
Пріоритет 4 є найвищим. |
4. Для даних попередньої задачі обчисліть час відгуку і час до завершення кожного потоку в разі використання всіх алгоритмів планування. Обчисліть також
середній час відгуку і поясніть одержані результати.
5.Як зміниться завантаження пристроїв введення-виведення із зменшенням довжини кванта у разі кругового планування? Чи збільшиться в цьому випадку
час виконання окремих задач?
6. Порівняйте продуктивності алгоритмів багаторівневих черг зі зворотним зв’язком і SRTCF для потоків, обмежених введенням-виведенням.
7. Опишіть, яким чином багаторівневі черги зі зворотним зв'язком відокремлюють потоки, обмежені процесором, від потоків, обмежених введенням-виведенням.
8. Припустімо, що в системі з лотерейним плануванням кількість квитків, одержуваних потоком, прямо пропорційна частці процесорного часу, який повинен
бути йому наданий:
а) запропонуйте критерій вибору наступного потоку для виконання, що базується на частці процесорного часу, використаній потоком, і кількості квитків, що у нього залишилися;
б) скільки квитків треба надати потоку при його створенні?
9. Деякі алгоритми планування при певних значеннях параметрів можуть емулювати один одного. Оцініть можливість прямої і зворотної емуляції таких пар
алгоритмів:
а) STCF і планування з пріоритетами;
б) FIFO і планування з пріоритетами;
в) FIFO і багаторівневих черг зі зворотним зв'язком;
г) STCF і кругового планування.
10. Проаналізуйте, як будуть поводитися застосування, розроблені для розв'язання
завдання 10 з розділу 3, якщо в їхньому коді змінювати пріоритети потоків Тіt
Дата добавления: 2014-12-20; просмотров: 148 | Поможем написать вашу работу | Нарушение авторских прав |