Home > Computers and Internet > ManualResetEvent ManualResetEventSlim and Thread.Yeild

ManualResetEvent ManualResetEventSlim and Thread.Yeild

Is there a difference in the behavior of a Thread when waking from a ManualResetEvent vs a ManualResetEventSlim when Thread.Yeild is involved? Yes, there is a difference in behavior!

The scenario is: If threads are woken up by an event and then call Thread.Yeild, does that Thread.Yeild wait for all of the threads to be woken up? With ManualResetEvent the answer is Yes, and the answer for ManualResetEventSlim the answer is No.

I wrote a little program in C# to test this out and was surprised by the difference in behavior. When using the ManualResetEventSlim, a Thread would wake up, Yield, and reset the slim event, before most of the other threads even woke up. As a result a single thread would be blocked behind the ManualResetEventSlim during multiple calls to Set and Reset. I’m guessing that the difference in behavior is due to the spin waits that ManualResetEventSlim does. The spins will sleep a Thread, and as a result Thread.Yield won’t wait for those threads.

The other thing that I learned in this program is that even though a Thread calls Thread.Start on another Thread, that doesn’t mean that its next call to Thread.Yeild will actually wait for the other Thread to be started.

Here is the program configured to use ManualResetEvent. If you want to see the behavior for ManualResetEventSlim change the type for the e variable, and switch the calls to WaitOne to Wait.

class Program
{
private static int counter = 0;
private static ManualResetEvent e = new ManualResetEvent(false);
static void Main(string[] args)
{
var threads = new Thread[20];
var allLogs = new List<List<Tuple<int,string>>>(21);
for (int i = 0; i < threads.Length; ++i)
{
var t = new Thread(obj =>
{
var logs = new List<Tuple<int, string>>();

int log = Interlocked.Increment(ref counter);
logs.Add(new Tuple<int, string>(log, "Waiting 1"));
e.WaitOne();
Thread.Yield();
e.Reset();

log = Interlocked.Increment(ref counter);
logs.Add(new Tuple<int, string>(log, "Waiting 2"));
e.WaitOne();
Thread.Yield();
e.Reset();

log = Interlocked.Increment(ref counter);
logs.Add(new Tuple<int, string>(log, "Waiting 3"));
e.WaitOne();
Thread.Yield();
e.Reset();

log = Interlocked.Increment(ref counter);
logs.Add(new Tuple<int, string>(log, "Waiting 4"));
e.WaitOne();
log = Interlocked.Increment(ref counter);
logs.Add(new Tuple<int, string>(log, "Done"));

lock (allLogs)
{
allLogs.Add(logs);
}
});
t.Start();
threads[i] = t;
}
try
{
var mainLogs = new List<Tuple<int, string>>();
int mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Yeild"));
Thread.Yield();
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Setting 1"));
e.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Setting 2"));
e.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Setting 3"));
e.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Setting 4"));
e.Set();
Thread.Sleep(TimeSpan.FromSeconds(1));
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Setting 5"));
e.Set();

bool allStopped = false;
while (allStopped == false)
{
allStopped = true;
for(int i = 0; i < threads.Length; ++i)
{
if (!(threads[i].ThreadState == ThreadState.Stopped || threads[i].ThreadState == ThreadState.StopRequested))
{
allStopped = false;
mainLog = Interlocked.Increment(ref counter);
mainLogs.Add(new Tuple<int, string>(mainLog, "Main Thread " + i + " is not Stopped"));
e.Set();
Thread.Yield();
break;
}
}
}

lock (allLogs)
{
allLogs.Add(mainLogs);
}

var logTuples = from logCollection in allLogs
from logTuple in logCollection
orderby logTuple.Item1
select logTuple;

foreach(var lt in logTuples)
{
Console.WriteLine($"{lt.Item1}\t{lt.Item2}");
}
}
catch(Exception ex)
{
Console.WriteLine(ex);
}
Console.ReadLine();
}
}

 

  1. No comments yet.
  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: