Synchronous Threading

Introduction

Once again, it's IPL, and it was Pollard who was batting. But this time, I did watch him. I sent a congrats Tweet to him, too, before writing this code for the article. Well, this article is basically to explain how to make threads run synchronously.

There are times in everyone's life when they need to do synchronization via two or more threads. Before proceeding, one may ask, what is synchronization? So before they ask that question, here is the basic idea of what it actually is.

What is Synchronous Operations?

The best real-world example that I can think of for explaining synchronization is when you are cooking. Imagine you are cooking Shahi Paneer (the most tasty Indian Dish, I just love it). Also, imagine that you have a gas stove with 4 burners. Now the recipe of the dish says.

  1. First, you need to cut the cheese (paneer) into small pieces.
  2. Put a frying pan with oil on a burner to get it hot.
  3. Put the cheese pieces into the pan and fry them until they are fried properly.
  4. Once they are fried, put them into the gravy that has been prepared before (how to prepare gravy is out of the scope of this article).

Now as you might observe, Step 1 and Step 2 can be done in parallel. That is to say, you can do both, cutting the cheese and warming the pan simultaneously. These are called Asynchronous Operations since they can be done in parallel, having nothing to do with one another.

But for Step 3, of course, you need both Step 1 and Step 2 to be complete. You cannot proceed to fry the cheese until the oil is warm and the cheese has been cut into pieces. Task 3, therefore, can be described as a synchronous task. You need to stop until both the preceding steps finish.

Similarly, you cannot proceed to Step 4 until you are done with Step 3. Step 4 therefore is also a synchronous operation.

How does it all look in code?

Just for the sake of brevity, let us assume that all the preceding four steps are carried out by four different threads.

In order to stop the execution of the threads, we need a class AutoResetEvent.

Example

private readonly AutoResetEvent m_autoreset = new AutoResetEvent(false);

Here is the entire code for my Cheese Program above.

Example

using System;
using System.Threading;
class Program
{
    readonly AutoResetEvent m_autoreset = new AutoResetEvent(false);
    static void Main(string[] args)
    {
        var me = new Program();
        var cutCheese = new Thread(me.CutCheese);
        var warmOil = new Thread(me.WarmOil);
        var frCheese = new Thread(me.FrCheese);
        var addToGravy = new Thread(me.AddToGravy);
        cutCheese.Start();
        warmOil.Start();
        // Wait for CutCheese and WarmOil to complete
        me.m_autoreset.WaitOne();
        frCheese.Start();
        // Wait for FrCheese to complete
        me.m_autoreset.WaitOne();
        addToGravy.Start();
    }
    private void CutCheese()
    {
        // Implement CutCheese logic here
    }
    private void WarmOil()
    {
        var me = new Program();
        // Implement WarmOil logic here

        // Signal that WarmOil has completed
        me.m_autoreset.Set();
    }
    private void FrCheese()
    {
        var me = new Program();
        // Implement FrCheese logic here
        // Signal that FrCheese has completed
        me.m_autoreset.Set();
    }
    private void AddToGravy()
    {
        // Implement AddToGravy logic here
    }
}

The line "me.m_autoreset.WaitOne();" will stop the execution of the code and keep it there until "me.m_autoreset.Set();" is called. The two threads, cutCheese and warmOil, will start, and further execution will be blocked until both are complete. Once done, the execution will resume, and henceforth.

The process therefore suggests that you can even process the asynchronous process synchronously. And at the end of the day, you will get a very good dish to eat.

Happy reading.


Similar Articles