48005 (572117), страница 3
Текст из файла (страница 3)
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);
// якщо все-таки не дочекалися,
// те виходимо з циклу чекання
if(result!= WAIT_TIMEOUT)
break;
}
...і т.д.
}
У документації по SDK затверджується, що для передачі кванта часу іншим потокам можна викликати функцію Sleep з параметром 0 (Sleep(0)). Тому в літературі по системному програмуванню рекомендують для стимуляції Windows до передачі кванта часу синхронізувати потоки, використовуючи функцію PeekMessage.
Лістинг 1. Обмеження доступу до масиву з використанням критичних розділів
// Масив значень.
int mas[1000];
// Семафор, що регулює доступ до критичного розділу.
CRITICAL_SECTION CritSec;
{
...
// Инициализируем семафор критичного розділу.
InitializeCriticalSection(&CritSect);
... // Текст програми.
// Видаляємо об'єкт критичного розділу.
DeleteCriticalSection(&CritSec);
}
// Перший потік: запис у масив даних.
DWORD thread1(LPVOID par)
{ // Запис значення в масив.
// Запит на вхід у критичний розділ.
EnterCriticalSection(&CritSec);
// Виконання коду в критичному розділі.
for(int i = 0;i<1000;i++)
{
mas[i] = i;
}
// Вихід із критичного розділу:
// звільняємо критичний розділ для доступу
// до нього інших задач.
LeaveCriticalSection(&CritSec);
return 0;
}
// Другий потік: зчитування даних з масиву.
DWORD thread2(LPVOID par)
{ // Зчитування значень з масиву.
int j;
// Запит на вхід у критичний розділ.
EnterCriticalSection(&CritSec);
// Виконання коду в критичному розділі.
for(int i = 0;i<1000;i++)
{
j = mas[i];
}
// Вихід із критичного розділу:
// звільняємо критичний розділ для доступу
// до нього інших задач.
LeaveCriticalSection(&CritSec);
return 0;
}
Лістинг 2. Обмеження доступу до масиву з використанням семафорів, що виключають
// Масив значень.
int mas[1000];
// Об'єкт, що регулює доступ до поділюваного коду.
HANDLE CritMutex;
{
...
// Инициализируем семафор поділюваного коду.
CritMutex = SectCreateMutex(NULL,FALSE,NULL);
... // Текст програми.
// Закриваємо об'єкт доступу до поділюваного коду.
CloseHandle(CritMutex);
}
// Перший потік: запис у масив даних.
DWORD thread1(LPVOID par)
{ // Запис значень у масив.
// Запит на вхід у захищений розділ.
DWORD dw = WaitForSingleObject(CritMutex,INFINITE);
if(dw == WAIT_OBJECT_0)
{ // Якщо об'єкт звільнений коректно, те
// виконання коду в захищеному розділі.
for(int i = 0;i<1000;i++)
{
mas[i] = i;
}
// Вихід із захищеного розділу:
// звільняємо об'єкт для доступу
// до захищеного розділу інших задач.
ReleaseMutex(CritMutex);
}
return 0;
}
// Другий потік: зчитування даних з масиву.
DWORD thread2(LPVOID par)
{ // Зчитування значень з масиву.
int j;
// Запит на вхід у захищений розділ.
DWORD dw = WaitForSingleObject(CritMutex,INFINITE);
if(dw == WAIT_OBJECT_0)
{ // Якщо об'єкт звільнений коректно, те
// виконання коду в захищеному розділі.
for(int i = 0;i<1000;i++)
{
j = mas[i];
}
// Вихід із захищеного розділу:
// звільняємо об'єкт для доступу
// до захищеного розділу інших задач.
ReleaseMutex(CritMutex);
}
return 0;
}
Лістинг 3. Зняття графічного потоку
void breakTask(GF_Task* tsk)
{
DWORD result;
char s[512];
// Команда задачі, що знімається, на зняття.
tsk->putState(tsBreak,True);
// Чекаємо завершення потоку протягом 1 с.
WaitForSingleObject(tsk->TaskHnd95,1000);
//
// Аналіз відповіді.
//
if(result == WAIT_OBJECT_0) // Ok - потік довершений успішно.
{
result = cmOK;
goto _L_EndbreakTask;
}
else if(result == WAIT_TIMEOUT) // Потік не відповідає.
{ // Підготовляємо рядок запиту.
sprintf(s,,
"Потік # %і не відповідає...\nобїект %s\n Зробіть вибір: \n\
'Так' - повторити команду на зняття \n\
'Немає' - зняти потік примусово \n\
'Скасувати' - не знімати потік"
TaskCollection->indexOf(tsk)+1,
tsk->getName());
}
// Висновок запиту на екран.
result = MsgBox(s, msg|msgSound);
switch(result) // Аналіз відповіді.
{
case cmNo: // Примусове зняття потоку.
tsk->putState(tsCrash,True); // Виставляємо прапор
tsk->endTask(); // Заключні операції
TerminateThread(tsk->TaskHnd95,0); // Знімаємо потік
goto _L_EndbreakTask;
case cmCancel: // Скасування зняття потоку.
goto _L_EndbreakTask;
}
}
else if(WAIT_FAILED) // Відбулася помилка доступу до об'єкта.
{ // Примусове зняття потоку.
SIL(); // Звуковий сигнал
tsk->endTask(); // Заключні операції
TerminateThread(tsk->TaskHnd95,0);
SIL(); // Звуковий сигнал
result = cmNo;
goto _L_EndbreakTask;
}
}
_L_EndbreakTask:
CloseHandle(tsk->TaskHnd95);
tsk->TaskHnd95 = 0;
tsk->putState(tsWorkTask,False); // Знімаємо прапори
return result;
}
// Код потоку, що знімається, приблизно наступний:
DWORD thread1(LPVOID par)
{
while((state & tsBreak) == 0)
{ // Поки прапор tsBreak не виставлений, виконуємо потік.
draw() // Щось виводимо на екран.
}
return 0;
}
Завдання на виконання
Використовуючи компілятор С++, або Assembler реалізувати програму синхронізації згідно варіанту. Під час роботи програми треба весь час виводити інформацію про те як працюють потоки (у файл, або реалізувати графічну візуалізацію). Якщо у Вашому завданні мова іде про розподіл ресурсів між потоками треба фіксувати звільнення і зайняття ресурсів потоками. При використанні механізму подій та семафорів треба фіксувати переходи у вільні стани (події) та переходи у сигнальний стан (таймери).
Написати з використанням подій програму, що реалізують таку схему за допомогою подій. Нехай є клієнт та сервер, які повинні спілкуватись між собою. Спочатку сервер (це один потік) просто чекає. Клієнт (другий потік) приймає у користувача повідомлення та передає його серверу. Сервер обробляє повідомлення, а саме: він формує нове повідомлення яке складається з n повторів початкового повідомлення, де n – кількість символів у початковому повідомленні. Весь цей час клієнт чекає, потім отримує відповідь і виводить її користувачу.
Виконати завдання №1 використовуючи механізм таймерів. (треба виставити достатній час для обробки запитів.)
Написати програму, що має два потока; один готує дані (наприклад зчитує з файла), а інший відсилає їх на сервер. Треба розпаралелити їх роботу. Тут потоки повинні працювати по черзі. Спочатку перший потік готує порцію даних. Потім другий потік відправляє її, а перший тим часом готує наступну порцію і т.д. (для такої синхронізації потрібно буде дві події “автосбросом”).
Написати з використанням м’ютекса програму, що створює десять процесів, кожен з яких у свою чергу створює десять потоків, у кожному з потоків треба підрахувати значення факторіалу сумі свого номеру (a) та номеру свого процесу (b), потім занести номер свого процесу (1-10), свій номер (1-10), та обчислене значення у файл (вхід у стек). Після цього кожен потік повинен обчислити значення ступеню a^b. Знову, аналогічним чином відмітитись у файлі та, якщо можна, залишити відмітку про вихід зі стеку. Якщо вийти зі стеку неможливо чекати і потім вийти. Таким чином кожен потік пише у файл два рази або один раз. Переконатись у тому, що є потоки, які не чекають своєї черги вийти зі стеку. (Стек повинен спрацювати за стандартним правилом: перший зайшов – останній вийшов.)
Виконати завдання №4 використовуючи механізм подій (детально продумайте схему, прийдеться використовувати досить багато подій).
Виконати завдання №4 використовуючи критичні секції.
Виконати завдання №4 використовуючи семафор.
Виконати завдання №4 з тією різницею, що потоки повинні створити чергу. (Черга працює за правилом FIFO. Перший зайшов – перший вийшов. Поки не вийдуть всі потоки перед данним, він повинен чекати).
Виконати завдання №5 з тією різницею, що потоки повинні створити чергу. (Черга працює за правилом FIFO. Перший зайшов – перший вийшов. Поки не вийдуть всі потоки перед данним, він повинен чекати).
Виконати завдання №6 з тією різницею, що потоки повинні створити чергу. (Черга працює за правилом FIFO. Перший зайшов – перший вийшов. Поки не вийдуть всі потоки перед данним, він повинен чекати).
Виконати завдання №7 з тією різницею, що потоки повинні створити чергу. (Черга працює за правилом FIFO. Перший зайшов – перший вийшов. Поки не вийдуть всі потоки перед данним, він повинен чекати).
Написати програму (використовувати м’ютекс та семафор), що створює 5 клієнтських та 2 серверних потока. Для кожного потока зафіксувати деякий період часу, який він чекає, а потім поміщає у чергу свій номер та номер свого запиту (1,2 і т.д.). Серверні потоки нічого не роблять поки у черзі не з’явиться хоча б один єлемент. Як тільки він з’явився один з серверних потоків обробляє його (пише у файл свій номер та отриманий запит). Після обробки потік “засинає” на фіксований час. Якщо в черзі більше 10 запитів програма зупиняється.
Підібрати такі значення часових проміжків, щоб черга переповнювалась.
Написати програму (використовуючи критичні секції та семафор), що аналогічна до програми з завдання №12. Кількість клієнтів - 2, кількість серверів – 4.
Використовуючи подію з ручним сбросом реалізувати наступне: Ваша програма повинна створити два потока. Один пише у файл (можна працювати просто з пам’ятю) 1000 одиниць і потім у циклі читає цей файл та змінює 1 на 0 та навпаки. (Після другої «прогонки» у файлі будуть лише нулю, потім тільки одиниці і т.д.). Другий потік повинен «просинатися» через фіксовані проміжки часу та підраховувати кількість одиниць у файлі.
За допомогою м’ютекса та таймера реалізувати наступне: Один потік просинається через однакові проміжки часу та додає 1 за модулем десять до числа у файлі (спочатку там нуль). Ваша програма повинна змоделювати будильник, що пікає кожну годину таке число разів, скільки записано у файлі.
Виконати завдання №15 використовуючи критичні секції та таймера.
Виконати завдання №15 використовуючи семафори та таймери.
Використовуючи подію і таймер написати програму, що створює два потока, що «працюють» по черзі (так само як у завданні №1, але потоком не треба обмінюватись повідомленнями). Ваша програма повинна моделювати будильник, який кожну годину дивиться який з процесів працює (№1 або №2) та пікає 1 або 2 рази відповідно.
За критичної секції та подій написати програму, що створює 11 потоків. Кожен з 10 перших потоків підраховує числа 10^10, 20^9, 30^8, 40^8, 50^7, 60^6, 70^5, 80^4, 90^2, 100^1 відповідно. Їх роботу необхідно синхронізувати таким чином, щоб вони по черзі писали результат у файл, а одинадцятий потік послідовно зчитував ці числа та додавав їх.
Написати програму з завдання №19 із використанням семафорів та подій.
Завдання на виконання
Використовуючи компілятор С++, або Assembler реалізувати програму синхронізації згідно варіанту:
1.Перевірити твердження SDK про те, що потоки мають дисципліну захоплення мютекса за правилом FIFO
2.Перевірити порядок виконання потоків після сигналізації події(event)
3. Написати бібліотеку роботи з комплексними числами в багатопоточному середовищі за допомогою критичної секції (одне блокування на всі потоки)
4.Написати бібліотеку роботи з комплексними числами в багатопоточному середовищі за допомогою повязаного з комплексним числом м’ютекса
5.Написати бібліотеку роботи з комплексними числами в багатопоточному середовищі за допомогою пов‘язаного з комплексним числом мютекса(окремо читання і для запису)
6. Написати бібліотеку роботи з векторами в багатопоточному середовищі за допомогою критичної секції (одне блокування на всі потоки)
7.Написати бібліотеку роботи з векторами в багатопоточному середовищі за допомогою повязаного з вектором м’ютекса
8.Написати бібліотеку роботи з векторами в багатопоточному середовищі за допомогою пов’язаного з вектором м’ютекса(окремо читання і для запису)
9.З‘ясувати дисципліну виконання потоків, які стояли в черзі по мірі звільнення семафора
10.Організувати синхронізацію між іменованими створеними обєктами за рахунок подій(event)
11.Написати бібліотеку, яка узагальнює поняття критичної секції на міжпроцесній взаємодії
12.Написати бібліотеку роботи зі стеком в багатопоточному середовищі за допомогою повязаного з вектором м’ютекса
13.Написати бібліотеку роботи зі стеком в багатопоточному середовищі за допомогою критичної секції (одне блокування на всі потоки)
14.Написати бібліотеку роботи зі стеком в багатопоточному середовищі за допомогою пов’язаного з вектором м’ютекса(окремо читання і для запису)
1000>1000>1000>1000>













