user3603343
user3603343

Reputation: 57

Thread synchronization printing strings

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

Answers (2)

Sinatr
Sinatr

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

Sriram Sakthivel
Sriram Sakthivel

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

Related Questions