Last active
April 2, 2026 18:34
-
-
Save sunmeat/1e2855aa2b4f28b7ccec92de5c1686c0 to your computer and use it in GitHub Desktop.
concurrent collections
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System.Collections.Concurrent; | |
| using System.Text; | |
| class Program | |
| { | |
| static void Main() | |
| { | |
| Console.OutputEncoding = Encoding.UTF8; | |
| // === ConcurrentDictionary: потокобезпечний список замовлень === | |
| var orders = new ConcurrentDictionary<int, string>(); | |
| var orderWorker1 = new Thread(() => | |
| { | |
| Console.WriteLine("[Менеджер] Додає замовлення..."); | |
| orders.TryAdd(101, "Прийнято в обробку"); | |
| /* Add (у звичайному Dictionary) | |
| - додає елемент; | |
| - якщо ключ вже існує → кидає виняток (ArgumentException). | |
| TryAdd (у ConcurrentDictionary) | |
| - намагається додати елемент; | |
| - якщо ключ уже існує → нічого не робить і повертає false, замість винятку; | |
| - якщо додавання вдалося → повертає true | |
| Така логіка дуже зручна у багатопоточності, де кілька потоків можуть одночасно | |
| працювати з колекцією, і винятки при зіткненні були б зайвим навантаженням! */ | |
| orders.TryAdd(102, "Прийнято в обробку"); | |
| orders.TryAdd(103, "Прийнято в обробку"); | |
| orders.TryAdd(104, "Прийнято в обробку"); | |
| }); | |
| var orderWorker2 = new Thread(() => | |
| { | |
| Thread.Sleep(100); | |
| Console.WriteLine("[Система] Оновлює статус замовлень..."); | |
| orders.AddOrUpdate(101, "Відправлено", (key, oldValue) => "Відправлено"); | |
| orders.AddOrUpdate(102, "Відправлено", (key, oldValue) => "Відправлено"); | |
| orders.TryRemove(104, out _); | |
| }); | |
| orderWorker1.Start(); | |
| orderWorker2.Start(); | |
| orderWorker1.Join(); | |
| orderWorker2.Join(); | |
| Console.WriteLine($"[Система] Підсумковий стан замовлень: {string.Join(", ", orders)}"); | |
| // === ConcurrentQueue: потокобезпечна черга завдань === | |
| var taskQueue = new ConcurrentQueue<string>(); | |
| var taskProducer1 = new Thread(() => | |
| { | |
| taskQueue.Enqueue("Пакування замовлення 101"); | |
| taskQueue.Enqueue("Пакування замовлення 102"); | |
| taskQueue.Enqueue("Пакування замовлення 103"); | |
| }); | |
| var taskProducer2 = new Thread(() => | |
| { | |
| taskQueue.Enqueue("Доставка замовлення 101"); | |
| taskQueue.Enqueue("Доставка замовлення 102"); | |
| }); | |
| taskProducer1.Start(); | |
| taskProducer2.Start(); | |
| taskProducer1.Join(); | |
| taskProducer2.Join(); | |
| while (taskQueue.TryDequeue(out var task)) // інлайн-змінна, скорочення string task; while (taskQueue.TryDequeue(out task)) | |
| { | |
| Console.WriteLine($"[Логістика] Виконуємо завдання: {task}"); | |
| } | |
| // === ConcurrentStack: потокобезпечний склад === | |
| var warehouse = new ConcurrentStack<int>(); | |
| var supplier1 = new Thread(() => | |
| { | |
| warehouse.Push(5001); | |
| warehouse.Push(5002); | |
| warehouse.Push(5003); | |
| Console.WriteLine("[Постачальник] Привіз три товари"); | |
| }); | |
| var supplier2 = new Thread(() => | |
| { | |
| warehouse.Push(6001); | |
| warehouse.Push(6002); | |
| Console.WriteLine("[Постачальник] Привіз два товари"); | |
| }); | |
| supplier1.Start(); | |
| supplier2.Start(); | |
| supplier1.Join(); | |
| supplier2.Join(); | |
| while (warehouse.TryPop(out int item)) | |
| { | |
| Console.WriteLine($"[Склад] Взяли товар {item} для збирання замовлення"); | |
| } | |
| // === ConcurrentBag: пул працівників === | |
| var workers = new ConcurrentBag<string>(); | |
| // застосовується: | |
| // - для зберігання великої кількості об'єктів, якими користуються різні потоки (наприклад, кешування даних чи збір об'єктів) | |
| // - коли порядок вилучення елементів не має значення (наприклад, пул об'єктів) | |
| // - якщо один потік частіше додає, а потім той самий потік забирає (у цьому випадку ConcurrentBag<T> працює швидше за інші структури) | |
| var workerThread1 = new Thread(() => | |
| { | |
| workers.Add("Працівник 1"); | |
| workers.Add("Працівник 2"); | |
| Console.WriteLine("[Відділ кадрів] Найняли двох працівників"); | |
| }); | |
| var workerThread2 = new Thread(() => | |
| { | |
| Thread.Sleep(50); | |
| workers.Add("Працівник 3"); | |
| workers.Add("Працівник 4"); | |
| Console.WriteLine("[Відділ кадрів] Найняли ще двох працівників"); | |
| }); | |
| workerThread1.Start(); | |
| workerThread2.Start(); | |
| workerThread1.Join(); | |
| workerThread2.Join(); | |
| Console.WriteLine("[Система] Підсумковий список працівників:"); | |
| foreach (var worker in workers) | |
| { | |
| Console.WriteLine($" - {worker}"); | |
| } | |
| // === емуляція роботи магазину === | |
| var rnd = new Random(); | |
| var processingOrders = new ConcurrentQueue<int>(); | |
| var processOrdersThread = new Thread(() => | |
| { | |
| foreach (var order in orders.Keys) | |
| { | |
| processingOrders.Enqueue(order); | |
| Console.WriteLine($"[Система] Замовлення {order} відправлено на обробку"); | |
| Thread.Sleep(rnd.Next(50, 150)); | |
| } | |
| }); | |
| var completeOrdersThread = new Thread(() => | |
| { | |
| Thread.Sleep(100); | |
| while (processingOrders.TryDequeue(out int order)) | |
| { | |
| orders[order] = "Завершено"; | |
| Console.WriteLine($"[Система] Замовлення {order} оброблено та завершено"); | |
| Thread.Sleep(rnd.Next(50, 150)); | |
| } | |
| }); | |
| processOrdersThread.Start(); | |
| completeOrdersThread.Start(); | |
| processOrdersThread.Join(); | |
| completeOrdersThread.Join(); | |
| Console.WriteLine("\n=== Підсумковий стан системи ==="); | |
| Console.WriteLine($"Замовлення: {string.Join(", ", orders)}"); | |
| Console.WriteLine($"Завдань у черзі: {taskQueue.Count}"); | |
| Console.WriteLine($"Залишилось товарів на складі: {warehouse.Count}"); | |
| Console.WriteLine($"Працівників: {workers.Count}"); | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment