Українська
Завдання
Відповідно до номера свого варіанта виконайте завдання обраного рівня складності.
Варіанти
Варіант 1. Продаж квитків у кінотеатр
1. Початковий рівень. Створити консольну програму, у якій 8 потоків-кас одночасно продають квитки на сеанс зі 100 місцями, кожна намагається продати 20 квитків. Спочатку виконати продаж без синхронізації, потім із lock і вивести для обох варіантів кількість проданих квитків та ознаку перепродажу місць.
2. Базовий рівень. Створити консольну програму, яка запитує кількість місць у залі (10–500) і кількість кас-потоків (1–32), перевіряє введення та моделює продаж: кожна каса в циклі продає випадкове вільне місце, доки місця не закінчаться. Програма виводить таблицю «каса – продано квитків» і перевіряє інваріанти: кожне місце продано рівно один раз, сума продажів дорівнює кількості місць.
3. Високий рівень. Створити консольний застосунок для стрес-тесту продажу квитків з опціями --seats, --cashiers, --runs і --mode unsafe|lock|interlocked та --help. Для кожного запуску програма виконує продаж, перевіряє інваріанти (немає подвійного продажу, немає непроданих місць), вимірює час і виводить таблицю «запуск – час, мс – порушень»; підсумковий рядок містить медіану часу та загальну кількість порушень. Некоректні опції повідомляються в потік помилок; код завершення 0, якщо порушень немає, 2 – якщо є, 1 – помилка аргументів.
Варіант 2. Банківські рахунки
1. Початковий рівень. Створити консольну програму з двома рахунками по 1 000 грн, у якій два потоки виконують по 10 000 переказів по 1 грн у протилежних напрямках з блокуванням обох рахунків у порядку зростання їхніх номерів. Вивести баланси та загальну суму, яка має залишитися 2 000 грн.
2. Базовий рівень. Створити консольну програму, яка запитує кількість рахунків (2–100), початковий баланс і кількість потоків, після чого потоки виконують 100 000 переказів між випадковими рахунками без переходу балансу в мінус. Блокування рахунків упорядковується за номером. Програма виводить кількість виконаних і відхилених переказів, загальну суму до і після та результат перевірки її незмінності.
3. Високий рівень. Створити консольний застосунок, який читає з CSV-файлу, заданого першим аргументом, рахунки у форматі номер;власник;баланс, а з другого файлу – перекази звідки;куди;сума, і виконує перекази в N потоках (опція --threads). Опція --naive вмикає блокування в порядку «звідки–куди» і виявлення зависання за таймаутом Join. Програма виводить таблицю рахунків із балансами до і після, кількість виконаних і відхилених переказів, контроль загальної суми та час; помилки формату рядків повідомляються з номером рядка в потік помилок.
Варіант 3. Склад інтернет-магазину
1. Початковий рівень. Створити консольну програму, у якій на складі 1 000 одиниць товару, а 10 потоків одночасно резервують по одній одиниці, доки товар не закінчиться. Залишок зменшувати CAS-циклом Interlocked.CompareExchange, щоб він не став від’ємним; вивести кількість резервувань кожного потоку та загальну суму.
2. Базовий рівень. Створити консольну програму, яка запитує початковий залишок товару та кількість потоків-покупців, кожен з яких резервує випадкову кількість (1–5 одиниць) у циклі. Резервування реалізувати двома способами – lock та CAS-циклом Interlocked.CompareExchange. Для кожного способу вивести час, кількість успішних і відхилених резервувань та перевірку, що зарезервовано рівно початковий залишок.
3. Високий рівень. Створити консольний застосунок, який читає з файлу перелік товарів артикул;залишок і моделює резервування замовлень з кількох позицій у N потоках (опції --threads, --orders, --method lock|interlocked|both, --help). Замовлення резервується повністю або не резервується зовсім. Програма виводить таблицю «метод – потоки – час, мс – виконано – відхилено» для N = 1, 2, 4, 8, 16, підсумкові залишки кожного товару у файл і повідомлення про порушення інваріантів.
Варіант 4. Автомийка на три бокси
1. Початковий рівень. Створити консольну програму, у якій 10 автомобілів-потоків миються на автомийці з трьома боксами, обмеженими SemaphoreSlim. Миття триває 200 мс. Програма виводить журнал подій «приїхав – почав миття – завершив» з часом від початку роботи.
2. Базовий рівень. Створити консольну програму, яка запитує кількість боксів, кількість автомобілів і діапазон тривалості миття в мілісекундах, перевіряє введення та моделює роботу автомийки на SemaphoreSlim. Для кожного автомобіля обчислюється час очікування; програма виводить таблицю «авто – очікування – миття» та середній і максимальний час очікування.
3. Високий рівень. Створити консольний застосунок для аналізу справедливості автомийки з опціями --boxes, --cars, --seed, --patience (максимальне очікування, після якого авто їде) та --help. Програма фіксує порядок приїзду й початку миття, обчислює кількість «обгонів» (авто почало митися раніше того, хто приїхав першим), середнє, медіану й максимум очікування, кількість відмов, завантаженість кожного бокса у відсотках і записує журнал подій у CSV-файл.
Варіант 5. Бібліотечний каталог
1. Початковий рівень. Створити консольну програму з каталогом книг у Dictionary<string, string> (ISBN – назва), захищеним ReaderWriterLockSlim. Чотири потоки-читачі шукають випадкові ISBN, один потік-письменник додає 10 нових книг. Вивести кількість знайдених книг кожним читачем і розмір каталогу наприкінці.
2. Базовий рівень. Створити консольну програму з каталогом книг (ISBN – назва), у якому потоки-читачі шукають випадкові ISBN, а кожен k-й запит додає нову книгу. Програма запитує кількість читачів, кількість пошуків і k та порівнює захист каталогу через lock і через ReaderWriterLockSlim. Для кожного варіанта вивести час, кількість знайдених книг і записів, а також відношення часу двох варіантів.
3. Високий рівень. Створити консольний застосунок, що завантажує каталог книг (ISBN – назва) з CSV-файлу; потоки-читачі шукають книги за ISBN, а частина запитів додає книги. Для частки записів 0 %, 1 %, 10 %, 50 % і 1, 2, 4, 8, 16 читачів (опції --file, --ops, --runs, --help) програма з прогріванням вимірює медіану часу для lock і ReaderWriterLockSlim і виводить таблицю з позначкою швидшого засобу. Результати записуються у CSV-файл, помилки читання – у потік помилок.
Варіант 6. Обідаючі філософи
1. Початковий рівень. Створити консольну програму, у якій п’ять філософів-потоків по 100 разів їдять, беручи дві виделки-замки. Взаємоблокування усунути впорядкуванням: кожен філософ бере спочатку виделку з меншим номером. Вивести кількість обідів кожного філософа й загальний час.
2. Базовий рівень. Створити консольну програму, яка запитує кількість філософів (2–20) і обідів та реалізує дві стратегії уникнення взаємоблокування: упорядкування виделок і офіціанта (SemaphoreSlim на N – 1 місце). Для кожної стратегії вивести час, кількість обідів кожного філософа та максимальний час очікування виделок.
3. Високий рівень. Створити консольний застосунок, який порівнює три стратегії (order, waiter, timeout з Monitor.TryEnter і випадковою затримкою) за пропускною здатністю (обідів за секунду) для заданої опціями --philosophers, --seconds і --strategy all|order|waiter|timeout конфігурації. Програма виводить таблицю «стратегія – обідів/с – мін. і макс. обідів філософа – повторних спроб», перевіряє відсутність голодування (кожен філософ поїв хоча б раз) і повертає код 2, якщо його виявлено.
Варіант 7. Сплячий перукар
1. Початковий рівень. Створити консольну програму-модель перукарні з одним перукарем і трьома кріслами очікування на основі Monitor.Wait і Monitor.Pulse. Десять клієнтів приходять з інтервалом 100 мс, стрижка триває 250 мс; клієнт, що не знайшов вільного крісла, іде. Вивести журнал подій.
2. Базовий рівень. Створити консольну програму, яка запитує кількість крісел очікування, кількість клієнтів, інтервал приходу та тривалість стрижки, перевіряє введення та моделює перукарню на моніторі. Програма виводить журнал подій, кількість обслугованих клієнтів, кількість відмов і середній час очікування.
3. Високий рівень. Створити консольний застосунок-модель перукарні з кількома перукарями (опції --barbers, --chairs, --clients, --seed, --help), у якому час приходу й тривалість стрижки генеруються випадково із заданим зерном. Програма записує журнал подій у файл, виводить таблицю «перукар – клієнтів – час роботи – простій» та статистику відмов; окремо обчислюється залежність частки відмов від кількості крісел від 0 до 10.
Варіант 8. Ліфт у багатоповерхівці
1. Початковий рівень. Створити консольну програму, у якій п’ять потоків-мешканців викликають ліфт на випадкові поверхи, а потік ліфта обслуговує виклики з черги, чекаючи нових викликів через Monitor.Wait. Вивести журнал «виклик – прибуття» з номерами поверхів.
2. Базовий рівень. Створити консольну програму, яка запитує кількість поверхів і мешканців та моделює ліфт з умовною змінною: мешканці додають виклики в спільну чергу, ліфт рухається в одному напрямку, забираючи попутні виклики. Програма виводить журнал руху, середній і максимальний час очікування викликів.
3. Високий рівень. Створити консольний застосунок-модель ліфта з опціями --floors, --residents, --duration і --policy fifo|sweep, який порівнює дві стратегії обслуговування за середнім і максимальним часом очікування для кожного поверху. Програма виводить таблицю поверхів, позначає поверхи, виклики з яких чекали понад утричі довше за середнє (ознака голодування), та повертає код 2, якщо такі поверхи є.
Варіант 9. Мережевий принтер
1. Початковий рівень. Створити консольну програму, яка захоплює іменований Mutex Local\PrinterDemo, виводить «Друк документа…», чекає 3 с і звільняє м’ютекс. Запустити два екземпляри програми одночасно й показати, що другий чекає завершення першого.
2. Базовий рівень. Створити консольну програму, яка запитує назву документа й кількість сторінок та «друкує» його (по 200 мс на сторінку), захопивши іменований Mutex. Якщо принтер зайнятий понад 5 с, програма повідомляє про таймаут. Обробити AbandonedMutexException та вивести час очікування й друку.
3. Високий рівень. Створити консольний застосунок черги друку, де кілька процесів-клієнтів (print <файл>) передають документи через спільну теку, а процес-принтер (printer) обробляє їх по одному, захоплюючи іменований Mutex. Опції: --pages-delay, --timeout, --help. Принтер веде журнал «документ – процес – очікування – друк» у CSV-файлі й виводить підсумкову таблицю; одночасний запуск двох принтерів виявляється іменованим м’ютексом і завершується з кодом 3.
Варіант 10. Голосування на виборах
1. Початковий рівень. Створити консольну програму, у якій 8 потоків-дільниць по 100 000 разів додають голос за випадкового з трьох кандидатів у спільний масив лічильників через Interlocked.Increment. Вивести голоси кожного кандидата та загальну кількість, що має дорівнювати 800 000.
2. Базовий рівень. Створити консольну програму, яка запитує кількість кандидатів, дільниць і виборців на дільниці, підраховує голоси в потоках і визначає максимальну явку дільниці через CAS-цикл Interlocked.CompareExchange. Вивести таблицю результатів з відсотками, переможця та перевірку суми голосів.
3. Високий рівень. Створити консольний застосунок, що читає протоколи дільниць з каталогу CSV-файлів (дільниця;кандидат;голоси), обробляє файли в N потоках (--threads), атомарно підсумовує голоси та знаходить дільницю з максимальною кількістю голосів CAS-циклом. Програма порівнює час для lock, Interlocked і локальних лічильників з підсумком, виводить результати виборів і таблицю часу, а некоректні рядки записує до окремого файлу помилок.
Варіант 11. Паркування аеропорту
1. Початковий рівень. Створити консольну програму з паркуванням аеропорту на 5 місць (SemaphoreSlim), до якого під’їжджають 12 автомобілів-потоків. Кожен чекає на місце не довше 300 мс, стоїть 400 мс і виїжджає. Вивести журнал подій і кількість відмов.
2. Базовий рівень. Створити консольну програму, яка запитує кількість місць для легкових авто, автобусів і таксі та моделює паркування з окремим семафором на кожну категорію. Для кожного авто задано категорію, час приїзду, стоянки та терпіння. Вивести таблицю за категоріями: обслуговано, відмов, середнє очікування.
3. Високий рівень. Створити консольний застосунок, що читає з CSV-файлу розклад приїздів час;номер;категорія;стоянка;терпіння, моделює паркування з квотами категорій (опції --cars, --buses, --taxis) та дозволяє таксі займати вільні місця легкових авто, якщо ті вільні понад половину. Програма виводить таблицю завантаженості за хвилинами моделювання, статистику відмов за категоріями та перевіряє, що квоти ніколи не перевищено.
Варіант 12. Кухня ресторану
1. Початковий рівень. Створити консольну програму, у якій кухар-потік готує 10 страв, а офіціант-потік забирає кожну готову страву. Передавання сигналу «страва готова» реалізувати через AutoResetEvent. Вивести журнал «приготовано – винесено».
2. Базовий рівень. Створити консольну програму, яка запитує кількість кухарів, офіціантів і замовлень та моделює кухню: кухарі кладуть страви на роздачу, офіціанти чекають сигналу AutoResetEvent і забирають страви. Вивести для кожного замовлення час приготування і затримку між готовністю та виносом, а також середню затримку.
3. Високий рівень. Створити консольний застосунок-модель кухні, що читає замовлення з файлу (столик;страва;час приготування) і порівнює дві реалізації роздачі – на AutoResetEvent і на Monitor.Wait/PulseAll – за середньою та максимальною затримкою виносу (опції --cooks, --waiters, --mode, --help). Програма виводить звіт за столиками, таблицю порівняння і попередження, якщо страва чекала на роздачі довше за заданий опцією --limit час.
Варіант 13. Естафета
1. Початковий рівень. Створити консольну програму, у якій чотири бігуни-потоки готуються різний час, а потім стартують одночасно після Barrier.SignalAndWait. Кожен «біжить» випадковий час (400–600 мс). Вивести порядок фінішу та час кожного бігуна.
2. Базовий рівень. Створити консольну програму, яка запитує кількість команд і етапів естафети та моделює забіг: на кожному етапі перші бігуни всіх команд стартують одночасно через Barrier, а завершення етапу всіма командами очікується за допомогою CountdownEvent. Вивести таблицю «команда – час етапів – сумарний час» і переможця.
3. Високий рівень. Створити консольний застосунок естафети з опціями --teams, --stages, --seed і --help, у якому етапи синхронізуються Barrier, фальстарт імітується потоком, що стартує до сигналу ManualResetEventSlim, і виявляється за часовими мітками. Програма виводить протокол кожного етапу, дискваліфікації за фальстарт, підсумкову таблицю команд із місцями і записує протокол у CSV-файл.
Варіант 14. Лічильник кліків реклами
1. Початковий рівень. Створити консольну програму, у якій 4 потоки реєструють по 1 000 000 кліків у спільному лічильнику без синхронізації та з Interlocked.Increment. Вивести отримані значення, очікуване значення та час кожного варіанта.
2. Базовий рівень. Створити консольну програму, яка запитує кількість кліків реклами й максимальну кількість потоків і вимірює час реєстрації кліків (збільшення спільного лічильника) способами lock (object), lock (Lock) і Interlocked для 1, 2, 4… потоків. Для кожного вимірювання виконується прогрівання і медіана п’яти запусків; вивести таблицю часу та перевірку, що лічильник дорівнює кількості кліків.
3. Високий рівень. Створити консольний застосунок для дослідження масштабованості лічильника кліків кампаній (масив лічильників за кампаніями) з опціями --clicks, --campaigns, --max-threads, --runs, --csv і --help. Порівнюються lock на весь масив, окремі замки для кожної кампанії, Interlocked і локальні лічильники з об’єднанням. Програма виводить таблицю часу, прискорення й ефективності для 1…N потоків, перевіряє суми та записує результати у CSV-файл.
Варіант 15. Бронювання готелю
1. Початковий рівень. Створити консольну програму з готелем на 10 номерів, у якій два потоки одночасно бронюють пари суміжних номерів (i та i + 1) у різному порядку. Взаємоблокування усунути блокуванням номерів у порядку зростання. Вивести заброньовані пари.
2. Базовий рівень. Створити консольну програму, яка запитує кількість номерів і потоків та моделює групові бронювання 2–4 випадкових номерів одночасно: бронювання виконується лише тоді, коли вільні всі номери групи. Замки номерів захоплюються в порядку зростання. Вивести кількість успішних і відхилених бронювань та перевірити, що жоден номер не заброньовано двічі.
3. Високий рівень. Створити консольний застосунок стрес-тесту бронювання на 16 потоках (опції --rooms, --threads, --seconds, --strategy ordered|trylock, --help), у якому стратегія trylock захоплює номери з таймаутом Monitor.TryEnter і відступає. Програма виводить пропускну здатність (бронювань за секунду), кількість повторів, таблицю завантаженості номерів і перевірку інваріантів; якщо протягом 5 с не виконано жодного бронювання, повідомляє про ймовірне взаємоблокування та повертає код 2.
Варіант 16. Пропускний пункт кордону
1. Початковий рівень. Створити консольну програму, у якій 10 автомобілів-потоків проходять один пункт контролю, захищений lock. Автомобілі мають пріоритет «звичайний» або «службовий». Вивести порядок проходження та час очікування кожного автомобіля.
2. Базовий рівень. Створити консольну програму, яка запитує кількість звичайних і службових автомобілів та моделює пункт контролю, де службові автомобілі пропускаються першими. Програма обчислює максимальний час очікування звичайних автомобілів і повідомляє про голодування, якщо він перевищує задану користувачем межу.
3. Високий рівень. Створити консольний застосунок пункту пропуску зі справедливою чергою на основі Monitor.Wait/PulseAll і номерів заявок (опції --lanes, --cars, --priority-share, --mode priority|fair, --help). У режимі fair після кожних трьох службових пропускається один звичайний автомобіль. Програма виводить таблицю «категорія – середнє, медіана, максимум очікування» для обох режимів і робить висновок про наявність голодування.
Варіант 17. Лабораторне обладнання
1. Початковий рівень. Створити консольну програму, у якій 4 потоки по 1 000 000 разів додають показники приладу до спільної суми, захищеної SpinLock. Вивести суму, очікуване значення і час виконання.
2. Базовий рівень. Створити консольну програму, яка запитує кількість потоків і операцій та порівнює SpinLock і lock для дуже короткої критичної секції (додавання до суми) і для довшої (додавання в список із 50 елементів з пошуком). Вивести таблицю часу для обох секцій і обох засобів.
3. Високий рівень. Створити консольний застосунок-бенчмарк з опціями --threads, --work (тривалість критичної секції в ітераціях Thread.SpinWait), --runs і --help, який будує таблицю «довжина секції – потоки – час SpinLock – час lock – швидший засіб» для довжин 1, 10, 100, 1 000, 10 000. Програма використовує прогрівання й медіану, записує CSV-файл і виводить межу довжини секції, після якої lock стає вигіднішим.
Варіант 18. Кешування курсів валют
1. Початковий рівень. Створити консольну програму, у якій потік оновлення кожні 100 мс замінює незмінний словник курсів валют новим методом Interlocked.Exchange, а три потоки-читачі без блокувань читають курс долара. Вивести 10 прочитаних значень кожним читачем.
2. Базовий рівень. Створити консольну програму, яка запитує кількість читачів і тривалість роботи та реалізує кеш курсів як незмінний об’єкт-знімок (record з часом оновлення), що замінюється Interlocked.Exchange. Читачі перевіряють узгодженість знімка (курс купівлі менший за курс продажу). Вивести кількість читань, оновлень і виявлених неузгоджених знімків (має бути 0).
3. Високий рівень. Створити консольний застосунок, що порівнює три реалізації кешу курсів: lock, ReaderWriterLockSlim і заміну незмінного знімка через Interlocked.CompareExchange (опції --readers, --update-ms, --seconds, --help). Курси зчитуються з CSV-файлу історії та «оновлюються» по черзі. Програма виводить таблицю «реалізація – читань за секунду – оновлень – максимальна затримка читання» і перевіряє узгодженість знімків.
Варіант 19. Міст з одностороннім рухом
1. Початковий рівень. Створити консольну програму-модель вузького мосту, яким одночасно можуть їхати лише автомобілі одного напрямку. Шість автомобілів-потоків (по три з кожного берега) чекають через Monitor.Wait, доки міст звільниться від зустрічних авто. Вивести журнал заїздів і виїздів.
2. Базовий рівень. Створити консольну програму, яка запитує кількість автомобілів з кожного берега та місткість мосту і моделює рух на моніторі: на мосту не більше заданої кількості авто одного напрямку. Програма перевіряє, що зустрічні авто ніколи не були на мосту одночасно, і виводить час очікування кожного берега.
3. Високий рівень. Створити консольний застосунок мосту з рухом колонами (опції --north, --south, --capacity, --batch, --help): після проходження колони з --batch авто напрямок змінюється, якщо на іншому березі хтось чекає, що усуває голодування. Програма порівнює режими без колон і з колонами за максимальним очікуванням кожного берега, виводить таблицю й перевірку безпеки руху.
Варіант 20. Ігровий сервер
1. Початковий рівень. Створити консольну програму з двома гравцями, кожен з яких має інвентар (список предметів) зі своїм замком. Два потоки по 1 000 разів обмінюються предметами між гравцями в різних напрямках з блокуванням інвентарів за ідентифікатором гравця. Вивести кількість предметів кожного гравця та загальну кількість.
2. Базовий рівень. Створити консольну програму, яка запитує кількість гравців і потоків та моделює випадкові обміни предметами між парами гравців без взаємоблокувань. Програма перевіряє, що загальна кількість предметів і кількість кожного типу предметів не змінилася, і виводить таблицю гравців.
3. Високий рівень. Створити консольний застосунок ігрового сервера, що завантажує гравців та їхні інвентарі з JSON-файлу, моделює торгівлю (обмін кількох предметів за золото) у N потоках (опції --threads, --trades, --help) з упорядкованим блокуванням і таймаутом Monitor.TryEnter. Програма зберігає підсумковий стан у файл, виводить статистику угод і відмов за таймаутом та перевіряє збереження золота й предметів.
Варіант 21. Спортзал
1. Початковий рівень. Створити консольну програму-модель спортзалу з трьома біговими доріжками (SemaphoreSlim) і вісьмома відвідувачами-потоками, кожен з яких тренується 300 мс. Вивести журнал подій і максимальну кількість одночасно зайнятих доріжок.
2. Базовий рівень. Створити консольну програму, яка запитує кількість тренажерів кожного з трьох типів і кількість відвідувачів. Кожен відвідувач виконує програму тренування з трьох тренажерів по черзі, займаючи дозвіл відповідного семафора. Вивести час тренування кожного відвідувача і середнє очікування кожного типу тренажерів.
3. Високий рівень. Створити консольний застосунок-модель спортзалу, що читає з файлу кількість тренажерів кожного типу і програми тренувань відвідувачів (послідовність тренажерів і тривалостей). Відвідувачі – потоки, тренажери обмежуються семафорами. Програма моделює роботу протягом --minutes (1 хвилина моделі = 10 мс) і виводить утилізацію кожного тренажера у відсотках, середню довжину черги та рекомендацію, який тренажер докупити. Опція --seed задає відтворюваність, --help – довідка.
Варіант 22. Логер подій
1. Початковий рівень. Створити консольну програму, у якій 5 потоків записують по 200 повідомлень у спільний текстовий файл через метод логера, захищений lock. Після завершення програма перевіряє, що файл містить 1 000 цілих рядків, і виводить результат перевірки.
2. Базовий рівень. Створити консольну програму, яка запитує кількість потоків і повідомлень та порівнює два логери: із блокуванням на кожен запис у файл і з накопиченням повідомлень у локальному буфері потоку та записом пакетами по 100 рядків під замком. Вивести час обох варіантів і перевірку кількості рядків.
3. Високий рівень. Створити консольний застосунок-бенчмарк логера з опціями --threads, --messages, --granularity global|per-file|batched, --out і --help. Варіант per-file пише повідомлення різних рівнів (Info, Warning, Error) у різні файли з окремими замками. Програма виводить таблицю часу та пропускної здатності (повідомлень за секунду), перевіряє, що жоден рядок не втрачено й не перемішано, і повертає код 2 у разі порушень.
Варіант 23. Пожежна тривога
1. Початковий рівень. Створити консольну програму, у якій 6 потоків-працівників виконують роботу в циклі й перевіряють ManualResetEventSlim «тривога». Через 1 с основний потік оголошує тривогу, і всі працівники завершують роботу. Вивести, скільки ітерацій виконав кожен.
2. Базовий рівень. Створити консольну програму, яка запитує кількість працівників і час до тривоги. Працівники чекають сигналу ManualResetEventSlim між кроками роботи з таймаутом 50 мс. Програма вимірює час реакції кожного працівника від Set до виходу і виводить таблицю та максимальний час реакції.
3. Високий рівень. Створити консольний застосунок системи оповіщення будівлі з поверхами та кімнатами (опції --floors, --rooms, --check-ms, --help), у якому кожна кімната – потік. Тривога поверху (ManualResetEventSlim на поверх) і загальна тривога (окремий сигнал) очікуються через WaitHandle.WaitAny. Програма виводить час евакуації кожного поверху, загальний час реакції та порівнює його для різних значень --check-ms.
Варіант 24. Лікарняні палати
1. Початковий рівень. Створити консольну програму з лікарнею на 6 ліжок, до якої надходять 10 пацієнтів-потоків. Ліжко займається через Monitor.TryEnter із таймаутом 200 мс на спільний реєстр ліжок; пацієнт, що не отримав ліжко, скеровується до іншої лікарні. Вивести розподіл ліжок і кількість відмов.
2. Базовий рівень. Створити консольну програму, яка запитує кількість палат, ліжок у палаті та пацієнтів і розподіляє пацієнтів по палатах з окремим замком на кожну палату. Пацієнт пробує палати по черзі з Monitor.TryEnter і таймаутом. Вивести таблицю заповненості палат, кількість відмов і середній час оформлення.
3. Високий рівень. Створити консольний застосунок, що читає з файлу надходження пацієнтів час;ПІБ;відділення;терміновість, моделює розподіл ліжок у відділеннях з таймаутами (опції --timeout, --speedup, --help) і першочерговим оформленням термінових пацієнтів. Програма виводить журнал, таблицю відділень із завантаженістю, кількість відмов за терміновістю та перевіряє, що жодне ліжко не зайнято двічі.
Варіант 25. Генератор ідентифікаторів замовлень
1. Початковий рівень. Створити консольну програму, у якій 8 потоків отримують по 10 000 ідентифікаторів замовлень від генератора на основі Interlocked.Increment. Програма збирає всі ідентифікатори й виводить кількість отриманих, кількість унікальних і мінімальне та максимальне значення.
2. Базовий рівень. Створити консольну програму, яка запитує кількість потоків і ідентифікаторів та генерує ідентифікатори формату ORD-yyyyMMdd-NNNNNN, де лічильник скидається на початку нового дня. Реалізувати генератор з lock і без синхронізації, для кожного вивести кількість дублікатів і час.
3. Високий рівень. Створити консольний застосунок генерації ідентифікаторів для кількох магазинів (опції --shops, --threads, --count, --method lock|cas|blocks, --help). Метод blocks видає кожному потоку блок із 1 000 номерів через CAS і далі працює без синхронізації. Програма перевіряє унікальність ідентифікаторів, виводить таблицю часу методів, кількість «дірок» у нумерації та записує вибірку ідентифікаторів у файл.
Варіант 26. Пороми через річку
1. Початковий рівень. Створити консольну програму, у якій пором місткістю 4 автомобілі відправляється, лише коли повністю завантажений. Вісім автомобілів-потоків чекають місця через Monitor.Wait, а пором будить їх Monitor.PulseAll. Вивести журнал рейсів.
2. Базовий рівень. Створити консольну програму, яка запитує місткість порома, кількість автомобілів і максимальний час очікування відправлення. Пором відправляється, коли завантажений повністю або минув час очікування. Вивести таблицю рейсів (номер, кількість авто, причина відправлення) і середнє очікування автомобілів.
3. Високий рівень. Створити консольний застосунок-модель переправи з двома поромами на протилежних берегах (опції --capacity, --cars, --wait, --seed, --help), автомобілями на обох берегах і умовними змінними на моніторах берегів. Програма виводить журнал рейсів, статистику рейсів кожного порома (завантаженість, порожні рейси), середнє очікування автомобілів на кожному березі та перевіряє, що кожне авто переправлено один раз.
Варіант 27. Виявлення взаємоблокування
1. Початковий рівень. Створити консольну програму, яка читає з клавіатури пари «потік очікує ресурс» і «потік утримує ресурс» до порожнього рядка, будує граф очікування потоків і виводить, чи є в ньому цикл.
2. Базовий рівень. Створити консольну програму, яка зчитує з текстового файлу граф розподілу ресурсів (рядки T1 holds R1, T1 waits R2), перевіряє коректність рядків, будує граф очікування «потік → потік» і виводить усі цикли взаємоблокування у вигляді T1 → T2 → T1 або повідомлення про їх відсутність.
3. Високий рівень. Створити консольний застосунок з обгорткою TrackedLock, яка під час захоплення реєструє в глобальному графі очікування, який потік чекає і хто утримує замок. Фоновий потік-детектор кожні 200 мс шукає цикли й виводить звіт з іменами потоків і замків. Програма містить сценарії --scenario transfer|philosophers|none та опцію --help і повертає код 2, якщо виявлено взаємоблокування.
Варіант 28. Livelock у коридорі
1. Початковий рівень. Створити консольну програму, у якій два потоки-«пішоходи» з двома замками-«сторонами коридору» захоплюють одну сторону, не отримавши другу, звільняють її й одразу повторюють спробу. Обмежити кількість спроб і вивести, скільки спроб зробив кожен потік до успіху або вичерпання ліміту.
2. Базовий рівень. Створити консольну програму, яка запитує кількість пішоходів і максимальну кількість спроб та порівнює стратегію повтору без затримки й стратегію з випадковою затримкою (randomized backoff). Вивести для кожної стратегії кількість успіхів, середню кількість спроб і загальний час.
3. Високий рівень. Створити консольний застосунок для дослідження livelock з опціями --walkers, --backoff none|fixed|random|exponential, --max-attempts, --runs і --help. Програма виконує кілька запусків кожної стратегії, виводить таблицю «стратегія – частка успішних запусків – середні спроби – медіана часу» та позначає стратегії, за яких виникав livelock (ліміт спроб вичерпано).
Варіант 29. Заправка з колонками
1. Початковий рівень. Створити консольну програму-модель заправки з двома колонками (SemaphoreSlim), до якої під’їжджають 6 легкових автомобілів і 2 вантажівки, які потребують обох колонок одночасно. Вивести журнал заправки й показати, скільки чекали вантажівки.
2. Базовий рівень. Створити консольну програму, яка запитує кількість колонок, легкових автомобілів і вантажівок (займають дві колонки) та моделює заправку з потоком легкових авто. Програма вимірює максимальне очікування вантажівок і повідомляє про голодування, якщо воно перевищує введену межу.
3. Високий рівень. Створити консольний застосунок заправки зі справедливим алгоритмом на моніторі: коли чекає вантажівка, нові легкові авто не займають колонки, доки вона не почне заправку (опції --pumps, --cars, --trucks, --mode greedy|fair, --help). Програма виводить таблицю «режим – середнє й максимальне очікування легкових і вантажних – пропускна здатність» і висновок, чи усунуто голодування.
Варіант 30. Наукові прилади
1. Початковий рівень. Створити консольну програму, яка перед «вимірюванням» захоплює іменований Semaphore ScienceLab на 2 дозволи (Windows), виводить час початку, чекає 2 с і звільняє дозвіл. Запустити 4 екземпляри одночасно й показати, що вимірюють не більше двох.
2. Базовий рівень. Створити консольну програму, яка приймає назву приладу й тривалість вимірювання як аргументи командного рядка, чекає на дозвіл іменованого міжпроцесного семафора з таймаутом, виконує вимірювання та дописує результат у спільний CSV-файл під захистом іменованого Mutex. Вивести час очікування та повідомлення про таймаут.
3. Високий рівень. Створити консольний застосунок-координатор, що запускає --processes процесів-вимірювачів (Process.Start, та сама програма в режимі вимірювача). Кожен вимірювач чекає на дозвіл іменованого семафора на --limit одночасних вимірювань, «вимірює» --duration мс і дописує часові мітки в спільний CSV-журнал. Після завершення координатор читає журнал, будує таблицю «процес – очікування – вимірювання», перевіряє, що ліміт жодного разу не перевищено, і повертає код 2 у разі порушення; --help.
Порядок виконання та захисту роботи
- Опрацювати теоретичні відомості та приклади розв’язання завдань.
- Для свого варіанта визначити спільні дані, критичні секції та умови, на які чекають потоки; обрати засоби синхронізації й обґрунтувати вибір.
- Створити в JetBrains Rider консольне рішення .NET 10 і реалізувати завдання обраного рівня складності.
- Перевірити коректність стрес-тестом: запустити програму кілька разів у конфігурації Release з різною кількістю потоків і переконатися, що інваріанти (суми, кількості, унікальність) не порушуються.
- Для завдань із замками перевірити відсутність взаємоблокування: пояснити порядок захоплення замків; за потреби дослідити зависання у вкладці Parallel Stacks налагоджувача Rider.
- Виміряти час роботи з різними засобами синхронізації або кількістю потоків і пояснити результати.
- Продемонструвати роботу програми викладачеві, пояснити програмний код і відповісти на контрольні питання.