5

I need a simple data structure with these requirements:

  • it should behave like a queue,
  • all the enqueue operations should be atomic.

I have very limited experience with multithreading, but this is what I came up to:

public class Tickets
{
    private ConcurrentQueue<uint> _tickets;

    public Tickets(uint from, uint to)
    {
        Initialize(from, to);
    }

    private readonly object _lock = new object();
    public void Initialize(uint from, uint to)
    {
        lock(_lock)
        {
            _tickets = new ConcurrentQueue<uint>();

            for (uint i = from; i <= to; i++)
            {
                _tickets.Enqueue(i);
            }
        }
    }

    public uint Dequeue()
    {
        uint number;
        if (_tickets.TryDequeue(out number))
        {
            return number;
        }

        throw new ArgumentException("Ticket queue empty!");
    }
}

First question: is this code ok?

Secod question: how can I unit test this class (for instance with two threads which are perfoming dequeue operation periodically on the queue with elements (1, 2, 3, 4, 5, 6) and the first thread should get only odd numbers and the second thread only the even numbers)? I tried this, but the asserts aren't executing:

[Test]
public void Test()
{
    var tickets = new Tickets(1, 4);
    var t1 = new Thread(() =>
                            {
                                Assert.AreEqual(1, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(3, tickets.Dequeue());
                            });


    var t2 = new Thread(() =>
                            {
                                Assert.AreEqual(2, tickets.Dequeue());
                                Thread.Sleep(100);
                                Assert.AreEqual(4, tickets.Dequeue());
                            });

    t1.Start();
    t2.Start();
}
sventevit
  • 4,766
  • 10
  • 57
  • 89
  • First Question's Answer: You collection is not thread safe because `Dequeue` can be called when `Initializ`ing. – Ahmed KRAIEM May 14 '13 at 13:49
  • 1
    Need to lock around your `Dequeue`. Also the concept that two threads will ideally interlace like that is flawed. It's not guaranteed that they will take it in turns like that, certainly not in the code you have given. – weston May 14 '13 at 13:51
  • @weston: I thought so, that's why I asked how to unit test this in proper way. – sventevit May 14 '13 at 13:55
  • 3
    Is there a reason you're not using the framework concurrent queue? http://msdn.microsoft.com/en-us/library/system.collections.concurrent.aspx – penguat May 14 '13 at 13:55
  • I'm not aware of a way to thoroughly test something's thread-safety through automated testing, although pex might manage it: http://research.microsoft.com/en-us/projects/pex/ – penguat May 14 '13 at 13:57
  • 1
    Is it important that they take from the queue in a "round robbin" way or was it just for the purpose of the test. i.e. in the real environment, do you care if thread 1 takes both 1 and 2 before thread 2 takes any? – weston May 14 '13 at 14:00

2 Answers2

5

I would use chess: http://research.microsoft.com/en-us/projects/chess

CHESS is a tool for finding and reproducing Heisenbugs in concurrent programs. CHESS repeatedly runs a concurrent test ensuring that every run takes a different interleaving. If an interleaving results in an error, CHESS can reproduce the interleaving for improved debugging. CHESS is available for both managed and native programs.

Lorenzo Dematté
  • 7,638
  • 3
  • 37
  • 77
4

The problem with multithreading and unit tests is one of timing. When you try to introduce multiple threads to unit tests you run the risk of non-reproducable test results, tests that pass sometimes but not other times.

But just to explain why your asserts may not be executing, the unit test completes before the threads. It needs to wait for the threads to complete rather than just kicking them off and moving on. It's also feasible that the unit test framework itself is not threadsafe or capable of Asserts being called from other threads.

Sorry it's not a solution, but I don't know of any automated testing solution for multithreaded code either.

See also: How should I unit test threaded code?

Community
  • 1
  • 1
weston
  • 54,145
  • 21
  • 145
  • 203