Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# Locks and Multi Threading on a queue

I am writing a multi threaded application and I have concerns with 2 threads access a queue

Thread 1 puts items in a queue for processing Thread 2 removes items from the queue to process

Thread 1 runs once a minute due to the nature of the data it is pulling. Thread 2 is always running, it removes an item from the queue and sleeps for 100ms. I have to do this to ensure that I don't overwhelm a service it calls when it dequeues an item.

I assume both threads should place a lock on the queue when adding or removing items from it. Are there any further considerations? For instance say Thread 1 has a lock and Thread 2 tries to access it. Does Thread 2 simply know to wait and resume once the lock is removed?

Would it be preferable to use a ConcurrentQueue and just TryDequeue and if it fails just go about its 100 ms sleep?

Thanks in advance

like image 368
Jordan Avatar asked Apr 14 '26 23:04

Jordan


2 Answers

It's even easier if you use a BlockingCollection<T> like I do in NuGet's VS console dispatcher for my PostKey/WaitKey implementation. The consuming thread calls Take(...) which will block until another thread calls Add(...). There is no need to poll. Additionally, you may wish to pass a cancellation token to the Take method so another thread can stop the consumer thread if it's currently waiting for an Add that will never come. Here are the relevant methods:

private readonly BlockingCollection<VsKeyInfo> _keyBuffer = 
      new BlockingCollection<VsKeyInfo>();
private CancellationTokenSource _cancelWaitKeySource;

// place a key into buffer
public void PostKey(VsKeyInfo key)
{
    if (key == null)
    {
        throw new ArgumentNullException("key");
    }
    _keyBuffer.Add(key);
}

// signal thread waiting on a key to exit Take
public void CancelWaitKey()
{
    if (_isExecutingReadKey && !_cancelWaitKeySource.IsCancellationRequested)
    {
        _cancelWaitKeySource.Cancel();
    }
}

// wait for a key to be placed on buffer
public VsKeyInfo WaitKey()
{
    try
    {
        // raise the StartWaitingKey event on main thread
        RaiseEventSafe(StartWaitingKey);

        // set/reset the cancellation token
        _cancelWaitKeySource = new CancellationTokenSource();
        _isExecutingReadKey = true;

        // blocking call
        VsKeyInfo key = _keyBuffer.Take(_cancelWaitKeySource.Token);

        return key;
    }
    catch (OperationCanceledException)
    {
        return null;
    }
    finally
    {
        _isExecutingReadKey = false;
    }
}

See http://nuget.codeplex.com/SourceControl/changeset/view/45e353aca7f4#src%2fVsConsole%2fConsole%2fConsole%2fConsoleDispatcher.cs for more details.

like image 77
x0n Avatar answered Apr 16 '26 13:04

x0n


As long as you are locking on the same "sync" object, thread 2 will wait for thread 1 and vice-versa. I think the ConcurrentQueue is a good idea because it's already specified as thread safe.

like image 26
swannee Avatar answered Apr 16 '26 12:04

swannee



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!