ProducerConsumer - five variants of the producer/consumer pattern#6
Conversation
Adds a learning project covering the producer/consumer pattern from a naive racy implementation up to a modern Channel<T>-based solution. Each variant is a standalone net10.0 console app sharing a single .slnx solution. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Adds a new ProducerConsumer learning project to the repo, showcasing five producer/consumer implementations from a deliberately broken baseline through progressively better synchronization approaches up to Channel<T>, bundled in a single .slnx solution.
Changes:
- Added
ProducerConsumer/README.mdassignment text (Czech) describing goals and questions for each variant. - Added
ProducerConsumer/ProducerConsumer.slnxsolution aggregating five standalone console projects. - Added five
net10.0console apps (Naive,Lock,MonitorWait,AsyncSemaphore,Channel) demonstrating different synchronization techniques.
Reviewed changes
Copilot reviewed 12 out of 12 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| ProducerConsumer/README.md | Documents the assignment, goals, and questions for each implementation variant. |
| ProducerConsumer/ProducerConsumer.slnx | New solution file grouping the five demo projects plus README. |
| ProducerConsumer/ProducerConsumer.Naive/Program.cs | Intentionally racy/busy-wait baseline implementation. |
| ProducerConsumer/ProducerConsumer.Naive/ProducerConsumer.Naive.csproj | New console project for the naive variant. |
| ProducerConsumer/ProducerConsumer.Lock/Program.cs | lock-protected queue access (still busy waiting). |
| ProducerConsumer/ProducerConsumer.Lock/ProducerConsumer.Lock.csproj | New console project for the lock variant. |
| ProducerConsumer/ProducerConsumer.MonitorWait/Program.cs | Uses Monitor.Wait/Pulse to remove busy waiting and handle shutdown. |
| ProducerConsumer/ProducerConsumer.MonitorWait/ProducerConsumer.MonitorWait.csproj | New console project for the Monitor variant. |
| ProducerConsumer/ProducerConsumer.AsyncSemaphore/Program.cs | Async consumer using SemaphoreSlim.WaitAsync() to avoid blocking a thread. |
| ProducerConsumer/ProducerConsumer.AsyncSemaphore/ProducerConsumer.AsyncSemaphore.csproj | New console project for the async semaphore variant. |
| ProducerConsumer/ProducerConsumer.Channel/Program.cs | Channel<T>-based async solution using ReadAllAsync + Complete(). |
| ProducerConsumer/ProducerConsumer.Channel/ProducerConsumer.Channel.csproj | New console project for the channel variant. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| finished = true; | ||
| available.Release(); // probudíme consumera, aby si všiml ukončení | ||
| }); | ||
|
|
||
| var consumerTask = Task.Run(async () => | ||
| { | ||
| while (true) | ||
| { | ||
| await available.WaitAsync(); // ASYNC čekání – neblokuje vlákno | ||
|
|
||
| int item; | ||
| lock (gate) | ||
| { | ||
| if (queue.Count == 0) | ||
| { | ||
| if (finished) return; | ||
| continue; |
There was a problem hiding this comment.
finished is written outside lock (gate) but read under the lock. This is a data race and the consumer may never observe finished == true, leading to a hang after the final available.Release() (consumer wakes, sees queue.Count == 0 and finished == false, continues, then blocks forever on the next WaitAsync). Write finished under the same lock (or use Volatile/Interlocked) and keep the shutdown signal and state change ordered/atomic with respect to the consumer.
There was a problem hiding this comment.
Fixed in acfd9ac — finished = true is now written inside lock (gate), ensuring the consumer always observes the flag correctly and preventing the hang.
Agent-Logs-Url: https://github.com/hakenr/Programiste.CSharp/sessions/9ac5c3ba-93c7-4804-acf8-35814985791d Co-authored-by: hakenr <12828888+hakenr@users.noreply.github.com>
Summary
Adds a new ProducerConsumer learning project that walks through the producer/consumer pattern from a naive racy implementation up to a modern
Channel<T>-based solution. Each variant is a standalonenet10.0console app, all collected under a single.slnxsolution.What's included
Program.cswith top-level statements:ProducerConsumer.Naive— sharedQueue<int>without synchronization. Intentionally buggy: race conditions and busy waiting.ProducerConsumer.Lock— atomic enqueue/dequeue vialock. Still busy waits.ProducerConsumer.MonitorWait—Monitor.Wait/Monitor.Pulse; consumer sleeps when the queue is empty. Useswhile(notif) to handle spurious wakeups;finishedflag +PulseAllfor shutdown.ProducerConsumer.AsyncSemaphore— async consumer usingSemaphoreSlim.WaitAsync()so the waiting thread is freed up.ProducerConsumer.Channel— modern solution usingSystem.Threading.Channelsandawait foreach, withWriter.Complete()for shutdown.Each variant produces N=20 items so the producer/consumer interleaving is visible in the console output.
Test plan
dotnet build ProducerConsumer/ProducerConsumer.slnx— succeeds, 0 warnings, 0 errors.Program.csare aligned with the matching README section.🤖 Generated with Claude Code