Reputation: 57
I wrote a small programm which prints "x", then "+", then again "x" and so on.
The idea was to make it run in two threads so that the first thread prints "x" and the second prints "+". The output looks like this:
"x" -> Thread number 1
"+" -> Thread number 2
"x" -> Thread number 1enter code here
"+" -> Thread number 2
and so on..
What I wrote seems to work fine but it seems to me it is written in very old-fashioned way:
public class Example
{
private static int count = 10;
private static int i = 0;
private static bool isOneActive = false;
private static void Run1(object o)
{
string s = o as string;
while(true)
{
if (!isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = true;
if (i++ > count) break;
}
}
}
private static void Run2(object o)
{
string s = o as string;
while(true)
{
if (isOneActive)
{
Console.WriteLine("Hello from thread number: " +
Thread.CurrentThread.ManagedThreadId + " -> " + s);
isOneActive = false;
if (i++ > count) break;
}
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
I know that now .NET has a lot of instruments for thread synchronization as for example ManualResetEvent class and Task library. So how could we write the same programm using ManualResetEvent class? Is it possible at all?
Upvotes: 3
Views: 243
Reputation: 21998
Consider this example (fiddle):
static void Main(string[] args)
{
var console = new object();
int i = 0;
Task.Run(() =>
{
lock (console)
while (i++ < 10)
{
Console.Write(i);
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Task.Run(() =>
{
lock (console)
while (i < 10)
{
Console.Write('+');
Monitor.Pulse(console);
Monitor.Wait(console);
}
});
Console.ReadLine(); // Task.WaitAll might be better, remove for fiddle
}
Upvotes: 3
Reputation: 73502
Your code isn't only old fashioned, it is very inefficient. It spins for no reason doing nothing but waiting; this is called Busy wait should be avoided whenever possible.
Better approach is to use Waithandles as noted in comments.
A naive implementation with very little change in your code will look something like the following.
public class Example
{
private static int count = 10;
private static int i = 0;
private static AutoResetEvent firstEvent = new AutoResetEvent(true);
private static AutoResetEvent secondEvent = new AutoResetEvent(false);
private static void Run1(object o)
{
string s = o as string;
while (true)
{
firstEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
secondEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
private static void Run2(object o)
{
string s = o as string;
while (true)
{
secondEvent.WaitOne();
Console.WriteLine("Hello from thread number: " + Thread.CurrentThread.ManagedThreadId + " -> " + s);
firstEvent.Set();
if (Interlocked.Increment(ref i) > count)
break;
}
}
static void Main()
{
Thread t1 = new Thread(Run1);
Thread t2 = new Thread(Run2);
t1.Start("x");
t2.Start("+");
}
}
Note that firstEvent
is instantiated with the initialState flag set to true
which means that first thread doesn't waits initially.
Upvotes: 4