HiveBrain v1.2.0
Get Started
← Back to all entries
patterncsharpMinor

Process dependent results of Producer/Consumer queue with explicit locking

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
processwithexplicitconsumerlockingresultsproducerqueuedependent

Problem

I have seen many examples which the results of a Producer/Consumer queue implemented using BlockingCollection are independent, e.g. each result can be consumed independently in parallel. For example, here the produces calculate a square root and consumers grab each result to update the UI.

I wonder whether explicit locking can be avoided if the consumers can NOT independently process each result calculated by producers. I created a demo example of this where each result has to be processed taking into account previous processed results in order to either insert a row to the data grid or update an existing data grid; it seems to work ok on some small data.

My questions are:

-
Can explicit locking be avoided?

-
How to encapsulate consumer and producer within a single object e.g. ProducerConsumerQueue which currently is really a producer queue.

-
Currently I use a separate task to process each result especially given it ultimately has to post back to the UI thread; is this a waste?

Below is the code behind a simple WinForm which only has a DataGridView and a button.

```
using System;
using System.Collections.Concurrent;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace PCQueueDemo
{
public partial class Form1 : Form
{
// to consume results that are depedent
private ConcurrentDictionary _dict = new ConcurrentDictionary();

private readonly object _sync = new object();
private BindingSource _bindingSource = new BindingSource();
private TaskScheduler _ui;
private ProducerConsumerQueue _producers;
private BlockingCollection _workQueue;
public Form1()
{
InitializeComponent();
_workQueue = new BlockingCollection();

// create 3 producers which will produce work item to the work queue.
_producers = new ProducerConsumerQueue(3, _workQueue);

Solution

Can explicit locking be avoided?

Sure, you can use immutable data structures with interlocked replacements. It's important to note that locking isn't bad, though - even BlockingCollection uses locks internally.

I'm not a huge fan of lockfree algorithms because they're incredibly complex, particularly with more relaxed memory models.


How to encapsulate consumer and producer within a single object e.g. ProducerConsumerQueue which currently is really a producer queue.

I would say it's a queue combined with producer logic. I'm not sure if you'd want to combine producer and consumer logic within the same class.


Currently I use a separate task to process each result; is this a waste?

For general producer/consumer systems, I would say no. In this particular case, I'd say yes, because every consumer task is run on the UI thread. This means they run one at a time. As a consequence of this, they do not need locks.

Context

StackExchange Code Review Q#161122, answer score: 4

Revisions (0)

No revisions yet.