Текст
                    1.
ПРОЦЕСИ, НИТКИ, ВОЛО
КНА ТА
ЗАВДАННЯ
Мета
:
вивчити можливості по створенню, керуванню виконанням
та завершенню процесів, ниток, волокон та
завдань
в операційній си
с-
темі
(ОС)
Windows.
1.1.
Теоретичні відомості
В
ОС
Windows підтримуються процеси, що скла
даються
з
декіл
ь-
кох ниток.
Процес
–
це об’єкт ядра, який має в своєму розпорядженні
д
е
який набір ресурсів.
Нитка
(також об’єкт ядра)
–
незалежн
а частина
проц
е
су, що
викон
ується, при цьому вона
розділяє з процесом спільний
адресний про
с
тір, код та змінні.
В
олокно
–
спрощена нитка, виконання
якої планується в програмі вручну.
Завдання
–
об’єкти ядра
, що вик
о-
нують роль контейнерів процесів. Розглянемо ці об’єкти д
о
кладніше.
1.1.1.
Процеси
Процесом зазвичай називають екземпляр
програми, що
викону
єт
ь-
ся
.
В деяки
х джерелах інформації не розрізнюють поняття
програм
и
і
процес
у
,
а
ле
вони фундаментально відрізняються один від одного. Пр
о-
грама є ст
а
тичним набором команд, а процес
–
це набір ресурсів і даних,
що викори
с
товуються при виконанні програми. Процес
(Process)
у
Windows складаєт
ь
ся з
таких
компонентів:
▪
с
труктура даних, що містить у
сю інформацію про процес, у тому
числі список відкритих дескрипторів різних системних ресурсів, унік
а-
льний ідентифікатор процесу, рі
зну статистичну інформацію і т.
ін
.;
▪
а
дресний пр
остір
–
діапазон адрес віртуальної пам'яті, яким може
к
о
ристуватися процес;
▪
в
иконувана програма і дані, що проектуються на віртуальний а
д-
ре
с
ний простір процесу.
Створення
процесу в системі
Win32
здійснюється завдяки виклику
о
д
нієї з таких функцій, як
Cre
ateProcess
,
CreateProcessAsUser
(для ОС


WinNT/2000) або CreateProcessWithLogonW (починаючи з ОС Win2000), і виконується в декілька етапів: ▪ Відкривається файл образу (EXE файл), який буде виконуватись у процесі. Якщо виконуваний файл не є Win32 прикладною програмою, то відбувається пошук образу підтримки (support image) для запуску цієї пр о грами. Наприклад, якщо виконується файл з розширенням .bat, то запуск а ється командний процесор, а саме програма cmd.exe . Примітка : В ОС WinNT/2000 реалізований такий мех анізм для завантаження пр о- грам: фу н кція CreateProcess після того, як знайде виконуваний Win32 файл, шукає в системному реєстрі за маршрутом HKEY_LOCAL - MACHINE \ SOFTWARE \ Microsoft \ WindowsNT \ CurrentVersion \ Image File Execution Option розділ з ім’ям і розширенням файл а , який запускається. Потім в ньому вказана фун к ція шукає параметр Debugger і, якщо рядок не пустий, запускає те, що в ньому записане, замість даної пр о грами. ▪ Створюється об’єкт ядра „п роцес ” . ▪ Створюється первинна нитка (стек, контекст і об’єкт ядра „ ни т- ка ” ). ▪ Підсистема Win32 сповіщається про створення нових процесу і ни т ки. ▪ Починається виконання первинної нитки. ▪ В контексті нового процесу і нитки ініціалізується адресний пр о- стір (наприклад, завантажуються необхідні DLL бібліотеки) і почин а- ється в и конання програми. Параметри виклику функції CreateProcess : BOOL CreateProcess ( LPCTSTR lpApplicationName, // ім’я файл а - прогр а м и LPTSTR lpCommandLine, // командний рядок викл и ку LPSECURITY_ATTRIBUTES lpProcessAttributes, // покажчи к на структуру атрибутів захисту пр оцесу LPSECURITY_ATTRIBUTES lpThreadAttributes, 
// пока ж чик на структуру атрибутів захисту нитки BOOL bInheritHandles, // ознака наслідування // дескри п торів процесу, що викликав функцію DWORD dwCreationFlags, // пр апорці створення // проц е су та призначення йому пріоритету LPVOID lpEnvironment, // покажчик на змінні // серед о вища LPCTSTR lpCurrentDirectory, // ім’я поточного // кат а логу LPSTARTUPINFO lpStar tupInfo, // покажчик на // структ у ру з параметрами вікна LPPROCESS_INFORMATION lpProcessInformation / / покажчик на структуру з даними про створений // пр о цес ); Функція CreateProcessAsUser та CreateProcessWithLogonW д о- зволя ють створити процес у контексті захисту користувача, це задає ться о д ним з параметрів виклику. Функція CreateProcessAsUser потребує виклику функції входу користувача до системи LogonUser . Процес завершується , якщо: ▪ Вхідна функція первинної нитки повернула управління. ▪ Одна з ниток процесу викликала функцію ExitPro cess . ▪ Нитка іншого процесу викликала функцію TerminateProcess . Коли процес завершується, всі User - і GDI - об’єкти, що були ств о- рені процесом, знищуються, об’єкти ядра закриваються (якщо їх не в и- корист о вує інший процес), адресний простір процесу також знищ ується. Параметри виклику вказаних функцій: VOID ExitProcess ( UINT uExitCode // код виход у для всіх ниток ); // п роц е су 
BOOL TerminateProcess( HANDLE hProcess, // дескриптор процесу UINT uExitCode // код виход у для процесу ); Приклад : п рограм а створює процес „ Калькулятор ” . Примітка : при створенні процесу функцією CreateProcess пар а- метр lpCommandLine повинен містити адресу рядка символів, а не кон с- танту (при виконанні функції командний рядок виклику процесу змін ю- ється, а при виході з функції – відно в люється). #include <windows.h> int main (int argc, char* argv[]) { STARTUPINFO si; PROCESS_INFORMATION pi; LPTSTR lpszSystemInfo; TCHAR tchBuff[MAX_PATH+1]; lpszSystemInfo = tchBuff; GetSystemDirector y (lpszSystemInfo,MAX_PATH+1); wsprintf(t chBuff,"%s \ \ calc.exe",lpszSystemInfo); ZeroMemory (&si, sizeof(si)); si.cb = sizeof(si); ZeroMemory( &pi, sizeof(pi) ); if (!CreateProcess (NULL, tchBuff, NULL, NULL, FALSE,0, NULL, NULL, &si, &pi)) return 0; // Закриття дескриптора CloseHandle ( pi.hProcess ); // процесу CloseHandle( pi.hThread ); // та основної нитки return 0; } 
1.1.2. Нитки Кожна нитка має: ▪ унікальний ідентифікатор нитки; ▪ вміст сукупності регістрів процесора, що відображають стан пр о- цесора взагалі ; ▪ два стека, один з як их використовується ниткою при її виконанні в режимі ядра, а другий – в режимі користувача ; ▪ закриту область пам’яті, що називається локальною пам’яттю н и- тки (TLS – T hread L ocal S torage) і яку використовують підсистеми ОС, run - time бібліотеки та DLL бібл іотеки (Dynamic Link Library). Щоб усі нитки, створені у системі, виконувались, ОС відводить кожній з них визначений інтервал процесорного часу. Тим самим ств о- рюється ілюзія одночасного виконання ниток (зрозуміло, що для баг а- топроц е сорних комп’ютерів можли вий дійсний паралелізм). В ОС Windows реалізована система планування з витісненням на основі прі о- ритетів, в якій завжди в и конується нитка , що готова до виконання та має найбільши й пріор и тет. О брана для виконання нитка виконується протя гом де як ого проміжку часу, що називається квантом . Квант в и- значає, скільки часу буде в и конуватись нитка, поки ОС не перерве її виконання. По закінченні кванта ОС перев і ряє, чи готова до виконання інша нитка з таким же (або більшим) рівнем пріоритету. Якщо такі ни т- ки не виявлен і, поточній нитці виділяється ще один квант. З іншого б о- ку , нитка може не повністю використати свій квант. Як тільки інша ни т- ка з більш високим пріоритетом стане готовою до вик о нання, поточна нитка витісняється, навіть якщо її квант ще не виче р паний. Квант не вимірюється в одиницях часу, він виражається цілим чи с- лом. Для кожної нитки зберігається поточне значення її кванта. Коли нитці в и діляється квант процесорного часу, це означає, що її квант установлюється в початкове значення. Воно залежить від ОС . Напр и- клад, для Win dows 2000 Professional початкове значення кванта дорі в- нює 6, а для Windows 2000 Server – 36. 
Кож ного раз у , коли виникає переривання від таймера, із кванта н и- тки віднімається число 3, і так доти, поки він не досягне нульового зн а- чення. Частота спрацьовування таймера залежить від апаратної платф о- рми. Наприклад, для більшості однопроцесорних x86 систем вона ст а- новить 10 мс, а для більшості багатопроцесорних x86 систем – 15 мс. У будь - якому випадку ОС повинна визначити, яку нитку виконув а- ти наступ ною. О бравши нову нитку, ОС переключає контекст. Ця оп е- рація полягає в тому, що зберігаються параметри нитки, яка щойно в и- конувалась (регістри процесора, покажчики на стеки ядра і користува ча , покажчик на адресний прост ір, у якому виконувалась вказана нитк а , та інш е ), і завант а жуються аналогічні параметри для другої нитки. Після цього починається в и конання нової нитки. Планування в ОС Windows здійснюється на рівні ниток, а не пр о- цесів. Це зрозуміло, тому що самі процеси не виконуються, а лише в и- діляють р е су рси і контекст для виконання ниток. Тому при плануванні ниток система не звертає уваг и на те, якому процесу вони належать. Н а- приклад, я к що процес А має 10 готових до виконання ни ток, а процес Б – дві, і всі 12 ниток мають однаковий пріоритет, то кожна з ни х отримає 1/12 проц е сорного часу. В ОС Windows існує 32 рівня пріоритету – від 0 до 31. Вони гр у- пуються так: 31 – 16 – рівні реального часу; 15 – 1 – динамічні рівні; 0 – систе м ний рівень, що зарезервований для процесу обнуління сторінок (zero - page thread). Пр іоритет кожної нитки (базовий пріоритет нитки) складається із пріоритету її процесу і відносного пріоритету самої нитки. Є сім відно с- них прі о ритетів ниток: ▪ n ormal – такий же, як і у процесу ; ▪ a bove normal – +1 до пріоритету процесу; ▪ b elow normal – – 1; ▪ h ighest – +2; ▪ l owest – – 2; 
▪ t ime critical – встановлює числове значення базового пріоритету ни т ки для Real time класу в 31, для решти класів – в 15; ▪ i dle – встановлює числове значення базового пріоритету нитики для Real time класу в 16, для решти к ласів – в 1. Якщо ОС функціонує на машині, де розміщено більше одного пр о- цесора, то, за замовчуванням, нитка виконується на будь - якому досту п- ному процесорі. Але в деяких випадках набір процесорів, на яких нитка може виконуватись, може бути обмеженим. Цю си туацію називають прив’язкою до процесорів (processor affinity). Можна змінити прив’язку до процесорів програмно, через Win32 - функції планування SetProcessAffinityMask , SetThreadAffinityMask (прив’язування проц е- су та нитки до конкре т ного процесор а ) та SetTh readIdealProcessor (встановлення бажаного процесор а нитки) . Для роботи з нитками використовуються такі функції (перерахов а- ні найбільш часто використовувані ) : CreateRemoteThread (створення нитки в адресному просторі іншого процесу), CreateThread (створення нитки в адресному просторі поточного процесу), ExitThread (заве р- шення роботи поточної нитки ) , GetCurrentThread (отримання псевд о- дескриптора поточної нитки), GetCurrentThreadId (отримання ідент и- фікатор а поточної нитки), GetExitCodeThread (отримання коду зав е р- шення нитки), ResumeThread (зменшення лічильник а зупинки нитки, коли дорівнює 0 – нитка продовжує виконання), SuspendThread (збіл ь- шення лічильнику з у пинки нитки, коли більше 0 – виконання нитки призупиняється), SwitchToThread ( звільнення процесор а від ви конання поточно ї нитк и та переключення на іншу ), TerminateThread (примус о- ве завершення нитки). Для створення нитки в адресному просторі пот о- чного процесу в фун к ції використовуються такі параметри: HANDLE CreateThread ( LPSECURITY_ATTRIBUTES lpThreadAttri butes, // пока ж чик на структуру атрибутів захисту SIZE_T dwStackSize , // розмір стек а для нитки, 
// 0 – задати розмір стека як у основної ни т ки LPTHREAD_START_ROUTINE lpStartAddress, // покажчик на функцію нитки LPVOID lpParameter, // параметр, що передається // ни т ці DWORD dwCreationFlags, // параметр створення, якщо // він містить CREATE_SUSPENDED – нитка // створюється в приз у пиненому стані LPDWORD lpThreadId // ідентифікатор нит к и, для // Windows NT/2000 та вище – може бути NULL ); 1.1. 3 . Волокна Волокна підтримуються в WIN32 API починаючи з Windows 2000. Як було сказано вище: в олокно – це спрощена нитка, виконання якої планується самою прикладною програмою, а не планувальником проц е- сорного часу ОС . Планування волокон може здійс нюватись шляхом п е- реключення на них тільки з інших волокон. Волокна виконуються в контексті ниток, в яких планується їх використання, і допускають повну їх ідентифікацію з нитками. В кожній нитці може бути заплановано д е- кілька волокон. Для кожного волокна створюється власний стек, в як о- му зберігається інформ а ція про стан волокна. Волокно може бути створене за допомогою функції CreateFiber із о с новної нитки процесу або отримане шляхом перетворення на волокно поточної нитки за допомогою функції ConvertThreadT oFiber . Пер е- ключення поміж волокнами може бути організоване за допомогою фу н- кції SwitchToFiber , але її в и клик можна здійснювати тільки із волокна. Пар аметри вказаних функцій : LPVOID CreateFiber ( SIZE_T dwStackSize, // розмір стек а для волокна, 
// 0 – з адати розмір стек а як у основної ни т ки LPFIBER_START_ROUTINE lpStartAddress, // покажчик // на функцію воло к на LPVOID lpParameter // параметр, що передається // вол о кну ); LPVOID ConvertThreadToFiber ( LPVOID lpParameter // параметр, що п ередає ться // вол о кну ); VOID SwitchToFiber ( LPVOID lpFiber // адреса волокна, яке запускаєт ь ся ); Для отримання параметру, що передається в волокно, використов у- єт ь ся функція GetFiberData . Для зворотного перетворення волокна на нитку використовує ться функція ConvertFiberToThread . Приклад. Програма створює чотири волокна, кожне з яких виконує п е реключення на наступне волокно. Якщо число переключень більше 10, робота пр о грами завершується. // задамо мінімальну версію ОС – Wi n dows 2000 #define _WIN 32_WINNT 0x0500 #define WINVER 0x0500 #include <windows.h> #include <stdio.h> #include <conio.h> int Counter; 
void *fiber[5]; void WINAPI Func(void *) { for (;;) { printf ("Fiber Number %d \ n",Counter%4); getch(); if ((Counter++)<10) { SwitchToFiber (fiber[Counter%4]); } else break; } } int main(int argc, char* argv[]) { Counter = 0; fiber[0] = CreateFiber (0,Func,NULL); fiber[1] = CreateFiber (0,Func,NULL); fiber[2] = CreateFiber (0,Func,NULL); fiber[3] = CreateFiber (0,Func,NULL); // для перемикання на пер ше волокно необх і д н о // перетв о рити поточну нит ку на волокно fiber[4] = ConvertThreadToFiber (NULL); SwitchToFiber (fiber[0]); return 0; } Для примусового знищення волокон застосовується функція DeleteFiber . Також для знищення волоко н можуть бути використані всі функції, які призначені для знищення ниток. Параметри функції зн и- щення волокн а : 
VOID DeleteFiber ( LPVOID lpFiber // покажчик на волокно для знище н ня ); 1.1.4. Функції очікування П ризупиня ти виконання нитки можна різними за соб ами . Функція Sleep призупиняє виконання нитки на задане число м і- лісекунд. Якщо я к аргумент даної функції вказати 0, то н итка відм о- виться від свого кванта процесорного часу, але негайно з’явиться в сп и- ску ниток, готових до виконання. Іншими словами, відб удеться навми с- не переключення ниток ( правильніше , спроба переключення – адже н а- ступною для виконання ниткою цілком імовірно може ст а ти та ж сама). Приклад. Програма створює процес „ Калькулятор ” і через 15 с е- кунд його знищує. #include <windows.h> int main (int argc, char* argv[]) { STARTUPINFO StartUpInfo; PROCESS_INFORMATION ProcessInfo; LPTSTR lpszSystemInfo; TCHAR tchBuff[MAX_PATH+1]; lpszSystemInfo = tchBuff; GetSystemDirectory(lpszSystemInfo,MAX_PATH+1); wsprintf(tchBuff,"%s \ \ calc.exe",lpszSyste mInfo); memset(&StartUpInfo,0,sizeof(STARTUPINFO)); StartUpInfo.cb = sizeof(STARTUPINFO); if (CreateProcess (NULL, lpszSystemInfo, NULL, NULL, FALSE,NORMAL_PRIORITY_CLASS,NULL, NULL,&StartUpInfo,&ProcessInfo)) { 
Sleep (15000); TerminateProcess (ProcessInfo.hProcess, 0); } ExitProcess (0); } Функція WaitForSingleObject призупиняє виконання нитки до тих пір, поки не відбудеться одна із двох подій: ▪ закінчиться час очікування; ▪ очікуваний об’єкт перейде в сигнальний (signaled ) стан. За значен ням, яке повертає ця функція, можна зрозуміти, яка з двох подій мала місце. Очікувати події за допомогою wait - функцій можна відн о сно більшості об’єктів ядра, наприклад, щодо об’єктів „ процес ” або „ нитка ” – щоб визначити, коли вони завершать свою роботу. В си г- нальний стан об’єкти переходять у таких ситуаціях: ▪ сповіщення ( Change notification ) – при змінах у файловій системі; ▪ введення з консолі ( Console input ) – при готовності вв едення з конс о лі; ▪ подія ( Event ) – при виклику функцій SetEvent або PulseEven t ; ▪ завдання ( Job ) – при завершенні; ▪ м’ютекс ( Mutex ) – якщо він не належить жодній нитці; ▪ процес ( Process ) – при завершенні; ▪ семафор ( Semaphore ) – при значенні більше 0; ▪ нитка ( Thread ) – при завершенні; ▪ таймер ( Waitable timer ) – при настанні вка заного часу . Функції WaitForMultipleObjects передається зразу масив об’єктів. Можна очікувати спрацювання зразу всіх об’єктів або якогось одного з них. Параметри вказаних функцій: DWORD WaitForSingleObject ( HANDLE hHandle, // дескриптор об’єкт а 
DWORD dwMilliseconds // інтервал очікування ); DWORD WaitForMultipleObjects ( DWORD nCount, // кількість дескрипторів у масиві CONST HANDLE *lpHandles, // масив дескрипт о рів // об’єктів BOOL bWaitAll, // параметр чекання (всі або один) DWORD dwMilliseconds // інтервал очікування ); Приклад. Програма створює дві однакових нитки і очікує їх заве р- ше н ня. Нитки просто виводять текстове повідомлення, яке передане їм при їх ініціалізації. Порядок вив едення повідомлення від першої та др у- гої нитки зумовлюється порядком їх виконання та не залежить від п о- рядку створе н ня. #include <windows.h> unsigned ThreadFunc (void * arg) { char ** str = (char**)arg; MessageBox (0,str[0],str[1],0); ExitThread (0); return 0; } int main(int argc, char* argv[] ) { char * InitStr1[2] = {"First thread","11111"}; char * InitStr2[2] = {"Second thread","22222"}; unsigned long uThreadIDs[2]; 
HANDLE hThreads[2]; hThreads[0] = CreateThread (NULL,0, (LPTHREAD_START_ROUTINE)ThreadFunc, InitStr1, 0,&uThreadIDs[0]); hThr eads[1] = CreateThread (NULL,0, (LPTHREAD_START_ROUTINE)ThreadFunc, InitStr2, 0,&uThreadIDs[1]); // Очікування завершення роботи ниток WaitForMultipleObjects (2, hThreads, TRUE, INFINITE); // Закриття дескрипторів CloseHandle (hThreads[0]); CloseHandle (h Threads[1]); return 0; } 1.1. 5 . Завдання Завдання (Job) – це об’єкт ядра ОС , що забезпечує керування о д- ним або декількома процесами як однією групою. Процес може входити одночасно тільки до одн ого за в д ання , і видалити процес із за в да ння н е- можливо. Всі про цеси, яки будуть запущені з процесу, що вже входить до за в да ння , також будуть входити до т ого ж за в да ння . За допомогою за в д ань можна встановлювати цілий ряд обмежень на виконання проц е- сів, що входять до за в да ння , при чому більшість обмежень не доступна при звичайному керуванні процесами. Саме тому для розширеного к е- рування яким - небудь пр о цесом доцільно створювати за в да ння , куди цей процес необхідно підкл ю чити . Для роботи з за в да ннями використовуються такі функції. AssignProcessToJobObject – д одавання процес у з дескриптором hProcess в існуюч е за в да ння з дескриптором hJob : BOOL AssignProcessToJobObject ( HANDLE hJob, // дескриптор за в да ння 
HANDLE hProcess // дескриптор процесу ); CreateJobObject – с творення об’єкт а - за в да ння з ім’ям lpName . HANDLE Cre ateJobObject ( LPSECUR ITY_ATTRIBUTES lpJobAttributes, // інформація про з а хист LPCTSTR lpName // необов’язкове ім’я за в да н ня ); IsProcessInJob – п еревірка, чи входить процес з дескриптором ProcessHandle у за в да ння з дескриптором JobHandle . BOOL IsPr ocessInJob ( HANDLE ProcessHandle, // дескриптор процесу HANDLE JobHandle, // дескриптор за в да ння PBOOL Result // покажчик на результат ); Відкриття існуючого об’єкт а - за в да ння з іменем lpName виконує фун к ція OpenJobObject . HANDLE OpenJobO bject ( DWORD dwDesiredAccess, // права доступу BOOL bInheritHandles, // дозвіл наслідування LPCTST R lpName // ім’я за в да ння ); Функція QueryInformationJobObject дозволяє о трима ти інформ а- ці ю про за в да ння з дескриптором hJob , а саме : обсяг в икористаного процесорного часу, лічильник кількості сторінкових відмов, пер е лік 
ідентифікаторів процесів, обмеження захисту. В полі JobObjectInfoClass задається тип інформації, а в полі lpJobObjectInfo – покажчик на відп о- відну стру к туру. BOOL QueryInforma tionJobObject ( HANDLE hJob, // дескриптор за в да ння JOBOBJECTINFOCLASS JobObjectInfoClass, // клас // інфо р мації про за в да ння LPVOID lpJobObjectInfo, // інформація про // обмеже н ня д ля вказаного класу DWORD cbJobObjectInfoLength, // розмір от риманої // інф о рмації LPDWORD lpReturnLength // розмір даних, що // зап и сані в структурі, на яку посилається // lpJobObjectInfo ); Встанов ити обмежен ня на процес и , що належать за в да нн ю з д е- скриптором hJob , дозволяє функція SetInformationJobOb ject , призн а- чення ї ї параметрів таке саме, як і в функції QueryInformationJobObject . BOOL SetInformationJobObject ( HANDLE hJob, // дескриптор за в да ння JOBOBJECTINFOCLASS JobObjectInfoClass, // клас // інфо р мації про за в да ння LPVOID lpJobObject Info // інформація про обмеження // для вказаного класу DWORD cbJobObjectInfoLength // розмір отрим а ної // інф о рмації ); 
За допомогою функцій QueryInformationJobObject та SetInformationJobObject можна отримувати або вносити обмеження, що перера ховані нижче (формат структур можна отримати в відпові д- них ро з ділах MSDN) . 1) Базові обмеження (значення параметра функцій JobObjectInfoClass = JobObjectBasicLimitInformation, lpJobObjectInfo вказує на структуру JOBOBJECT_BASIC_LIMIT_INFORMATION або JobObj ectInfoClass = JobObjectExtendedLimitInformation, lpJobObjectInfo вк а зує на структуру JOBOBJECT_EXTENDED_LIMIT_ INFORMATION) . ▪ Максимальна кількість активних процесів – обмеження на кіл ь- кість процесів, що одночасно виконуються. ▪ Загальн е обмеження на про цесорний час у режимі користувача – о б меження процесорного часу на всі процеси, що входять до за в да ння . Я кщо час буде вичерпано – всі процеси будуть завершені примусово. ▪ Індивідуальне обмеження на процесорний час у режимі корист у- вача – обмеження процесор ного часу для кожного процесу окремо. В разі вик о ристання всього часу – процес буде примусово завершений. ▪ Клас планування за в да ння – встановлюється довжина квант а часу для ниток процесів, які входять до за в да ння . ▪ Прив’язування до процесорів – для кожно го процесу встановл ю- ється маска прив’язування до процесор а ( для багатопроцесорних комп’ютерів ) . ▪ Клас пріоритету для всіх процесів – обмеження максимального прі о ритету для кожного процесу. Якщо нитка спробує підвищити свій пріор и тет – він залишається без зміни, але помилки виконання операції не б у де. ▪ Мінімальний та максимальний розміри робочого набору – для кожного процесу встановлюються обмеження на робочий набір , тобто на кіл ь кість сторінок, що постійно знаходяться в оперативній пам'яті . Р озмір зад а єть ся в байта х . 
▪ Обмеження віртуальної пам’яті – вказується максимальний ро з- мір віртуального адресного простору, який можна передати процесу або вс ьому з а в да нню . 2) Базові обмеження інтерфейсу користувача (значення параметр а ф у нкцій JobObjectInfoClass = JobO bjectBasicUIRestrictions , lpJobObjectInfo вк а зує на структуру JOBOBJECT_BASIC_ UI_RESTRICTIONS ) . ▪ Заборона роботи з буфером обміну – обмеження читання та оч и- ще н ня буфер а обміну. ▪ Заборона завершення роботи системи – забороняється вихід з с и- ст е ми або заве ршення роботи всієї системи через функцію ExitWindowsEx . ▪ Заборона зміни системних параметрів – кожному процесу забор о- няється змінювати параметри системи за допомогою функції SystemParametersInfo . До системних параметрів відносяться: параме т- ри робочого ст ол а , пристрою вв едення , системного меню, вікон пр о- грам, жи в лення і програми збереження екран а та ін . ▪ Заборона зміни параметрів екран а – забороняється зміна параме т- рів за допомогою функції ChangeDisplaySettings . ▪ Заборона створення та перемикання робочих столів – заборон я- ється використання функцій CreateDesktop та SwitchDesktop . ▪ Заборона користування USER - об’єктами, що не входять у за в да н- ня – процеси у за в да нн і не можуть звернутися до будь - яких USER - об’єктів, що створені зовнішніми до за в да ння процесами . Наприклад, неможливо отр и мати HWND дескриптор процесу, який не входить у за в да ння . 3) Базові обмеження захисту (значення параметр а функцій JobObjectInfoClass = JobObjectSecurityLimitInformation , lpJobObjectInfo вк а зує на структуру JOBOBJECT_SECURITY_LIMI T_INFORMATION ) . Примітка : якщо в за в да нн і ввести такі обмеження, скасувати їх буде неможл и во. ▪ Заборона доступу адміністратору. 
▪ Заборона маркер а необмеженого доступу. ▪ Блокування доступу – блокується доступ по ідентифікаторам з а- хисту (Security ID). Якщ о задати в функції QueryInformationJobObject в параметрі JobObjectInfoClass значення JobObjectBasicAccountingInformation , JobObjectBasicAndIoAccountingInformation або JobObjectBasicProcessIdList , можна отримати статистичну інформацію про за в да ння , а саме : в першому випадку – про кількість процесів у з а- в да нн і, процесорний час, кількість сторінкових відмов ; у другому вип а- дку – про кількість операцій читання, запису та про кількість переданих байтів ; у третьому випадку – перелік ідентифікаторів процесів, що вх о- дять до за в да ння . В п а раметрі lpJobObjectInfo відповідно повинен бути покажчик на структуру JOBOBJECT_BASIC_ACCOUNTING_ INFORMATION , або JOBOBJECT_BASIC_AND_IO_ACCOUNTING_ INFORMATION , або JOBOBJECT_BASIC_PROCESS_ID_LIST. Завершення всіх процесів у за в да н н і з ідентифікатором hJob може в и конуватися за допомогою функції TerminateJobObject : BOOL TerminateJobObject ( HANDLE hJob, // дескриптор за в да ння UINT uExitCode // код завершення ); Приклад. У програмі, що наведен а нижч е, в змінну lpszSystemInfo з аноситься шлях до системного каталогу Windows , який повертається фун к цією GetSystemDirectory , та додається до нього ім’я програми calc.exe. Далі створюється за в да ння MyJob з дескриптором hJob , для н ього встановлюється обмеження ( з групи базов их обмежен ь ) н а кіл ь- кість активних проц е сів (4) та виконується спроба запустити та додати 10 процесів з програми ca lc.exe. Далі програма очікує 15 секунд та зав е- ршує примусово всі проц е си в за в д а нн і. Як результат – буде створено 10 процесів, але одразу при додаванні їх в за в да ння , тільки перші чот и- 
ри будуть активними, інші будуть примусово завершені. Примітка : п е- рший рядок програми вказує, що пр о грама призначена для роботи в ОС Windows 2000 або вище, оскільки підтримка за в да нь у сист е мах Windows 95, 98 відсутня. #define _WIN32_WINNT 0x500 #include <windows.h> #include <stdio.h> HANDLE hJob; LPTSTR lpszSystemInfo; TCHAR tchBuff[MAX_PATH+1]; STARTUPINFO si; PROCESS_INFORMATION pi; int AddProcess2Job(void) { for (int i=0;i<10;i++) { ZeroMemory (&si, sizeof(si)); si.cb = s izeof(si); ZeroMemory (&pi, sizeof(pi)); if (!CreateProcess (NULL, tchBuff, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) return 0; AssignProcessToJobObject (hJob,pi.hProcess); } } int main(int argc, char* argv[]) { JOBOBJECT_BASIC_LIMIT_INFORMATIO N jInfo; lpszSystemInfo = tchBuff; GetSystemDirectory (lpszSystemInfo, MAX_PATH+1); w sprintf (tchBuff,"%s \ \ calc.exe",lpszSystemInfo); hJob = CreateJobObject (NULL, "MyJob"); 
jInfo.LimitFlags = JOB_OBJECT_LIMIT_ACTIVE_PROCESS; jInfo.ActiveProcessLimit = 4; SetInformationJobObject (hJob, JobObjectBasicLimitInformation, &jInfo, sizeof(jInfo)); AddProcess2Job (); Sleep (15000); TerminateJobObject (hJob,0); return 0; } 1.2. Контрольні завдання Розробити консольну програму в середовищі програмування Visual C + + , яка реалізує простий менеджер програм: дозволяє запускати вказ а- ні програми та завершувати їх (за вибором користувача) згідно з вим о- гами, що задаються варіантами , наведеними нижче . При завершенні р о- боти ро з робленого менеджер а всі запущені ним програми по винні бути примусово завершені. Для реалізації обов’язково використовувати ни т- ки (або волокна) та за в да ння . 1 . Запуск необмеженої кількості програм калькуляторів (сalc.exe) , кожна з яких виконується не більше 10 секунд. 2 . Запуск програм калькулятор а (calc .exe) , графічного редактора Paint (mspaint.exe) та блокнота (notepad.exe) загальною кількістю не б і- льше 5 екземплярів. 3 . Запуск програм калькулятора (сalc.exe) та графічного редактора Paint (mspaint.exe) кількі с тю не більше трьох екземплярів кожн а . 4 . Зап уск програм калькулятора (сalc.exe) , графічного редактора Paint (mspaint.exe) та бло к нота (notepad.exe) не більш ніж по одному екземпляру та їх вибіркове завершення. 5 . Запуск необмеженої кількості програм калькулятора (сalc.exe) та вибіркове їх завершення (передбачити також одночасне завершення всіх копій). 
6 . Запуск не більше 10 копій одночасно редакторів WordPad (write.exe) з заб о роною використання для них буфер а обміну. 7 . Запуск не більше п’яти редакторів WordPad (write.exe) , при зав е- ршенні роботи вида ти всю доступну статистичну інформацію про роб о- ту редакторів. 8 . Запуск не більше 10 програм калькуляторів (сalc.exe) , сумарний час вик о нання яких не перевищує хвилин и . 9 . Запуск будь - якої кількості програм калькулятора (сalc.exe) , гр а- фічного редактора Pai nt (mspaint.exe) , блокнота (notepad.exe) та реда к- тор а WordPad (write.exe) , та вибіркове їх завершення або завершення групами (групи ф о рмуються за типам и програм). 10 . Запуск програм калькулятора (сalc.exe) , графічного редактора Paint (mspaint.exe) , блокнот а (notepad.exe) та редактора WordPad (write.exe) за такою схемою: користувач о бирає, яку програму запуст и- ти . Я кщо вказана програма завершується, автоматично запускається наступна із списку , і так для всіх програм . Користувач може о брати будь - яку програму д ля запуску, автоматично п о винні запускатися всі інші програми із списку. 11 . Запуск та завершення вказаних користувачем програм (ім ена зада ю ться з клавіатури, каталог для програм за замовчанням – систе м- ний). За команд ою з клавіатури також виводити перелік назв файлів програм, які були у с пішно запущені на виконання , та з віт про невдалі спроби запуску.