Контрольная работа: Особливості багатозадачності в середовищі Windows
// команда потоку, що знімається, на зняття tsk->putState(tsBreak,True);
// збільшуємо відносний пріоритет
// потоку, що знімається, до максимально можливого
SetThreadPriority(tsk->TaskHnd95, THREAD_PRIORITY_TIME_CRITICAL)
// чекаємо завершення потоку протягом 1 з
WaitForSingleObject(tsk->TaskHnd95,1000);
}
Результату ніякого (вірніше, результат той же - вихід зі значенням WAIT_TIMEOUT). Виходить, що підвищення пріоритету не завжди спрацьовує (ще однією докір Microsoft).
Що ж робити? Як змусити потік, у якому працює програма зняття breakTask, передати керування іншим потокам? При одержанні значення WAIT_TIMEOUT починає виконуватися та частина коду, що виводить на екран вікно з запитом про те, що ж робити з потоком, що не знімається. У момент висновку вікна на екран багатостраждальний потік раптом сам завершується - він нарешті "зауважує" прапорець завершення і виходить з нескінченного циклу. Це підтверджує, що до потоку, що знімається, просто не доходить керування (не виділяється квант часу).
Не вдаючись у причини подібного поводження Windows, ми повинні проаналізувати, а що ж усе-таки відбувається в модальному вікні, що змушує ОС помітити нашу задачу. Імовірно, усе криється в петлі чекання подій, що запускається в модальному вікні. Однієї з основних функцій у такому циклі чекання є функція GetMessage. Чудовою властивістю володіє дана функція: її виклик приводить до оповіщення планувальника задач Windows. Оскільки зовнішніх подій для потоку, що викликав цю функцію, ні, те частину, що залишилася, його кванта часу планувальник задач передає іншому потоку, що виконується. Таким чином, наш потік, що знімається, знову оживає.
Отже, нам треба використовувати функцію типу GetMessage для стимуляції Windows до передачі керування іншим потокам. Але сама функція GetMessage нам не підходить, тому що вона віддає керування тільки в тому випадку, якщо для потоку з'явилося повідомлення. Замість GetMessage можна застосувати функцію PeekMessage, що перевіряє, є чи повідомлення в черзі для даного потоку, і незалежно від результату відразу ж повертає керування. Перепишемо наш попередній приклад так:
void breakTask(GF_Task* tsk)
{
DWORD result;
char s[512];
// команда потоку, що знімається, на зняття
tsk->putState(tsBreak,True);
// збільшуємо його відносний пріоритет
// до максимально можливого
SetThreadPriority(tsk->TaskHnd95,
THREAD_PRIORITY_TIME_CRITICAL)
int cnt = 1000/20;
// чекаємо завершення потоку протягом приблизно 1 з
while(cnt-)
{ // стимулюємо Windows до передачі кванта часу
// іншим потокам
PeekMessage(&_Msg,0,0,0,PM_NOREMOVE);
// чекаємо завершення потоку
result = WaitForSingleObject(tsk->TaskHnd95,20);