Question

I am running a MS unit test in VS2010 to test my multi-threaded application.

The application uses an AutoResetEvent to synchronise threads, which is declared like so:

private readonly AutoResetEvent captureParsedEvent = new AutoResetEvent(false);

Main test thread (ID: 13)

The main test thread launches a thread to parse a capture file, and then calls WaitOne() on a AutoResetEvent, blocking until the capture is complete:

int id = Thread.CurrentThread.ManagedThreadId;
CaptureManager.Instance.StartProcessingPackets();
Trace.WriteLine("[" + id + "]: WAITING ON CaptureParsedEvent");
captureParsedEvent.WaitOne();
Trace.WriteLine("[" + id + "]: WAITING ON CaptureParsedEvent DONE!");

// Analyse parsed capture...

(Side note: the code originally had a call to captureParsedEvent.Reset() after WaitOne() but I removed this while investigating this problem, as my research has concluded that this may not be necessary for AutoResetEvent objects.)

Parsing thread (ID: 18)

Meanwhile, the thread which is doing the parsing signals the AutoResetEvent like this:

private void InstanceManagerStateChanged(ManagerStateEventArgs ea, object sender)
{
    int id = Thread.CurrentThread.ManagedThreadId;
    switch(ea.CurrentState)
    {
        case ManagerState.ReadPacketsDone:
            Trace.WriteLine("\t[" + id + "]: CaptureParsedEvent SIGNAL");
            captureParsedEvent.Set();
            Trace.WriteLine("\t[" + id + "]: CaptureParsedEvent DONE!");
            break;
    }
}

Normally, everything behaves well and I see the following expected output in the output window:

[13]: WAITING ON CaptureParsedEvent
    [18]: CaptureParsedEvent SIGNAL
    [18]: CaptureParsedEvent DONE!
[13]: WAITING ON CaptureParsedEvent DONE!

However, I am seeing the following output intermittently:

[13]: WAITING ON CaptureParsedEvent
[13]: WAITING ON CaptureParsedEvent DONE!

This is obviously causing me issues because the capture hasn't really finishing parsing.

The above place is the only occurrence of captureParsedEvent.Set(); so I know that nobody else is signalling the event.

A few questions:

  1. Is Trace.WriteLine() thread-safe and outputting the traces in the correct order?

  2. I have only seen this issue when running unit tests in VS2010 -- is there something funny going on with tests being run in parallel, and usage of threads in this scenario that may be causing issues? My understanding is that the tests run in serial, but not sure if this is correct.

Was it helpful?

Solution 3

I have resolved my issue.

It turns out that for each packet that the code was processing, it was adding the InstanceManagerStateChanged() callback to the list of delegates:

CaptureManager.Instance.ManagerStateChanged += InstanceManagerStateChanged;

but we weren't correctly unsubscribing, which meant that I may have been getting notifications from the previous packet.

Unsubscribing prior to processing the next packet fixed this issue:

CaptureManager.Instance.ManagerStateChanged -= InstanceManagerStateChanged;

OTHER TIPS

It seems that what you're getting is caused by the fact that at the time of evaluation, ea.CurrentState is not ManagerState.ReadPacketsDone, so it's skipping the code inside that case statement. ManualResetEvents don't set themselves and if they did, then it would be a HUGE problem for everybody (I've never heard of somebody else having such a problem), so you just have to make sure that nobody else is setting the event.

To question 1: Trace.WriteLine() is thread safe, but if you have multiple threads making calls to writeline you are not guaranteed that those calls will get executed in order. However, in your case the SIGNAL and DONE messages will be written one after the other since they're executed in the same thread. More importantly, if you get the correct state, then at least CaptureParsedEvent SIGNAL will be printed before WAITING ON CaptureParsedEvent DONE because it happens before you set the manual reset event. After you signal, you're not guaranteed the order of prints for the WAITING ON CaptureParsedEvent DONE and CaptureParsedEvent DONE.

If another thread is writing at the same time, then it can write something in between them. But as I already said: it's most likely caused by ea.CurrentState not being ManagerState.ReadPacketsDone.

To question 2: when you're dealing with concurrency, there is always "something funny" going on or it's as "funny" as what you normally get with concurrent programming: you just have to thread carefully. Again, I don't think your issue is coming from concurrency, it just simply looks like you're not handling the correct case and/or somebody else has access to the same ManualResetEvent.

By default Visual Stufio 2010 does not run tests in parallel, you must enable this by manually editing the test settings file (parallelExecutionCount=0).

In looking at the code you've provided, the culprit may be related to the fact that the signaling is done within a singleton (CaptureManager.Instance). There may be situations where previous tests have already executed and the ManagerState has already completed. Try running the test by itself to validate this assumption.

If you're running the tests sequentially you may need to reset the state of the singleton between tests to avoid side-effects like this. Note, however, this must be done everywhere the singleton is used, which may prove to be less than ideal if this class is used heavily throughout the code-base.

If you're running the tests in parallel, all bets are off because you cannot guarantee a well known state at the time the test executes. Your best option is to redesign the relationships between objects so that the graph can be instantiated and executed without side effects.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top