Українська
Підсумки
Висновки
Спільні дані, до яких звертаються кілька потоків, створюють стан гонитви: навіть counter++ складається з кількох дій і втрачає оновлення. Коректна синхронізація забезпечує безпеку, живучість і справедливість. Найдешевший спосіб – позбутися спільного стану; для окремих змінних використовують атомарні операції Interlocked і CAS-цикли, для складених дій – lock з окремим об’єктом Lock або Monitor. Умовні змінні Monitor.Wait/PulseAll дозволяють чекати умову всередині критичної секції; SemaphoreSlim обмежує кількість потоків, ReaderWriterLockSlim пропускає багато читачів, а ManualResetEventSlim, CountdownEvent і Barrier координують потоки. Mutex і Semaphore з іменем синхронізують процеси. Взаємоблокування виникає за чотирьох умов Коффмана; на практиці його запобігають упорядкуванням замків і таймаутами, а діагностують у Rider (Parallel Stacks) і dotnet-dump. Крім взаємоблокувань, живучість порушують голодування, livelock, інверсія пріоритетів і конвої блокувань. Будь-яка критична секція виконується послідовно, тому вибір засобу та зернистості блокувань перевіряють вимірюваннями.
Питання для самоперевірки
- Що таке спільний стан, критична секція та стан гонитви?
- Чому операція
counter++не є атомарною? Які ще операції неатомарні? - Сформулюйте вимоги безпеки, живучості та справедливості.
- Сформулюйте умови Бернштейна й наведіть приклад їх порушення.
- Які методи має клас
Interlocked? Як працює CAS-цикл? - Для чого призначено модифікатор
volatileі чого він не гарантує? - На що компілятор перетворює оператор
lockдля типуLockта для інших типів? - Які об’єкти не можна використовувати для блокування і чому?
- Як працюють
Monitor.Wait,PulseіPulseAll? Чому умову перевіряють у цикліwhile? - Чим відрізняються
Mutex,SemaphoreіSemaphoreSlim? - Коли
ReaderWriterLockSlimефективніший заlock? Що таке режим оновлення? - Чим відрізняються
ManualResetEventSlim,AutoResetEvent,CountdownEventіBarrier? - Назвіть умови Коффмана. Які способи запобігання взаємоблокуванню порушують кожну з них?
- Як знайти взаємоблокування за допомогою Rider і
dotnet-dump? - Що таке голодування, livelock, інверсія пріоритетів і конвой блокувань?
Корисні посилання
- Огляд засобів синхронізації: https://learn.microsoft.com/dotnet/standard/threading/overview-of-synchronization-primitives
- Рекомендації щодо багатопотоковості: https://learn.microsoft.com/dotnet/standard/threading/managed-threading-best-practices
- Оператор
lock: https://learn.microsoft.com/dotnet/csharp/language-reference/statements/lock - Клас
Lock: https://learn.microsoft.com/dotnet/api/system.threading.lock - Клас
Interlocked: https://learn.microsoft.com/dotnet/api/system.threading.interlocked SemaphoreіSemaphoreSlim: https://learn.microsoft.com/dotnet/standard/threading/semaphore-and-semaphoreslim- Утиліта
dotnet-dump: https://learn.microsoft.com/dotnet/core/diagnostics/dotnet-dump - Налагодження взаємоблокування: https://learn.microsoft.com/dotnet/core/diagnostics/debug-deadlock
- Багатопотокове налагодження в Rider: https://www.jetbrains.com/help/rider/Debugging_Multithreaded_Applications.html