Tell me more ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

The scenario is as follows:
There are a couple of low priority threads that can be interrupted by high priority threads. Whenever a high priority thread asks the low priority threads to pause, they will go to wait state (if they are not in wait state already). However when a high priority thread signals that the low priority threads can resume, the low priority threads should not resume until all the high priority threads that asked the low priority threads to pause have consented.

To solve this I am keeping a track of Pause() calls in a counter variable. If counter value after the increment the value was 1, it means the threads were not in wait, so ask them to go in wait state. Otherwise just increment counter value. On the contrary when a high priority thread calls Resume() we decrement the counter value and if after the decrement the value is 0, it means the low priority threads can resume now.

Here is a simplified implementation of my problem. I am not comfortable with is the comparison operation in if statements with Interlocked.XXX, as the read/modify and comparison operations are not atomic. Am I missing something here? I don't want to use thread priority.

using System;
using System.Collections.Generic;
using System.Threading;

namespace TestConcurrency
{

// I borrowed this class from Joe Duffy's blog and modified it
public class LatchCounter
{
    private long _remain;
    private EventWaitHandle m_event;
    private readonly object _lockObject;

    public LatchCounter()
    {
        _remain = 0;
        m_event = new ManualResetEvent(true);
        _lockObject = new object();
    }

    public void Check()
    {
        if (Interlocked.Read(ref _remain) > 0)
        {
            m_event.WaitOne();
        }
    }

    public void Increment()
    {
        lock(_lockObject)
        {
           if (Interlocked.Increment(ref _remain) == 1)
               m_event.Reset();
        }
    }

    public void Decrement()
    {
        lock(_lockObject)
        {
           // The last thread to signal also sets the event.
           if (Interlocked.Decrement(ref _remain) == 0)
               m_event.Set();
        }
    }
}



public class LowPriorityThreads
{
    private List<Thread> _threads;
    private LatchCounter _latch;
    private int _threadCount = 1;

    internal LowPriorityThreads(int threadCount)
    {
        _threadCount = threadCount;
        _threads = new List<Thread>();
        for (int i = 0; i < _threadCount; i++)
        {
            _threads.Add(new Thread(ThreadProc));
        }

        _latch = new CountdownLatch();
    }


    public void Start()
    {
        foreach (Thread t in _threads)
        {
            t.Start();
        }
    }

    void ThreadProc()
    {
        while (true)
        {
            //Do something
            Thread.Sleep(Rand.Next());
            _latch.Check();
        }
    }

    internal void Pause()
    {
        _latch.Increment();
    }

    internal void Resume()
    {
        _latch.Decrement();
    }
}


public class HighPriorityThreads
{
    private Thread _thread;
    private LowPriorityThreads _lowPriorityThreads;

    internal HighPriorityThreads(LowPriorityThreads lowPriorityThreads)
    {
        _lowPriorityThreads = lowPriorityThreads;
        _thread = new Thread(RandomlyInterruptLowPriortyThreads);
    }

    public void Start()
    {
        _thread.Start();
    }

    void RandomlyInterruptLowPriortyThreads()
    {
        while (true)
        {
            Thread.Sleep(Rand.Next());

            _lowPriorityThreads.Pause();

            Thread.Sleep(Rand.Next());
            _lowPriorityThreads.Resume();
        }
    }
}

class Program
{
    static void Main(string[] args)
    {
        LowPriorityThreads lowPriorityThreads = new LowPriorityThreads(3);
        HighPriorityThreads highPriorityThreadOne = new HighPriorityThreads(lowPriorityThreads);
        HighPriorityThreads highPriorityThreadTwo = new HighPriorityThreads(lowPriorityThreads);

        lowPriorityThreads.Start();
        highPriorityThreadOne.Start();
        highPriorityThreadTwo.Start();
    }
}


class Rand
{
    internal static int Next()
    {
        // Guid idea has been borrowed from somewhere on StackOverFlow coz I like it
        return new System.Random(Guid.NewGuid().GetHashCode()).Next() % 30000;
    }
}

}

share|improve this question

Know someone who can answer? Share a link to this question via email, Google+, Twitter, or Facebook.

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.