Semaphore – synchronizing threads and processes

Semaphore is a mechanism similar to mutex and lock, but there are a few differences:
a) Semaphore can allow more than one thread to access critical section.
b) Semaphore can synchronize processes.

Imagine we have four threads. Every one writes a text A, B, C or D one hundred times.

        public void StartWithoutSynchronization()
        {
            //this task prints A
            var taskA = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("A " + i);
                }
            });

            //this task prints A
            var taskB = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("B " + i);
                }
            });

            //this task prints A
            var taskC = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("C " + i);
                }
            });

            //this task prints A
            var taskD = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("D " + i);
                }
            });

            taskA.Start();
            taskB.Start();
            taskC.Start();
            taskD.Start();
            Task.WaitAll(taskA, taskB, taskC, taskD);

            Console.WriteLine("Finished");
        }

If we run this code all thread will work simultaneously as there is no synchronization.
Now imagine we want to have only two threads working at a time. We can do it with semaphore.
Synchronizing threads:

        public void StartSynchronizedWithSemaphore()
        {
            var semaphore = new Semaphore(2, 2); // initialized to allow two thread at a time from beginning to the end

            //this task prints A
            var taskA = new Task(() =>
            {
                semaphore.WaitOne(); // waits if blocked; if can go - it decreases counter in semaphore
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("A " + i);
                }
                semaphore.Release(); // releases semaphore - counter is increased
            });

            //this task prints A
            var taskB = new Task(() =>
            {
                semaphore.WaitOne();
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("B " + i);
                }
                semaphore.Release();
            });

            //this task prints A
            var taskC = new Task(() =>
            {
                semaphore.WaitOne();
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("C " + i);
                }
                semaphore.Release();
            });

            //this task prints A
            var taskD = new Task(() =>
            {
                semaphore.WaitOne();
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("D " + i);
                }
                semaphore.Release();
            });

            taskA.Start();
            taskB.Start();
            taskC.Start();
            taskD.Start();
            Task.WaitAll(taskA, taskB, taskC, taskD);

            Console.WriteLine("Finished");
        }

When you run this code you will see that only two threads are running. The next one thread starts only when one of the previous threads is finished.

Synchronizing processes
Imagine new situation. We have an application and we want maximally two application instances processing at a time. We can initialize a semaphore with a name – it will work for all processes. We create an application with single method in it:

        public void StartSynchronizedProcessWithSemaphore()
        {
            //when name is passed into constructor - you synchronize processes
            var semaphore = new Semaphore(2, 2, "SemaphoreDemoApp"); 

            semaphore.WaitOne();
            Console.WriteLine("Application is processing... " + DateTime.Now.ToLongTimeString());
            Thread.Sleep(TimeSpan.FromSeconds(15));
            Console.WriteLine("Application stops processing... " + DateTime.Now.ToLongTimeString());
            semaphore.Release();
        }

Now we can compile and run the same application i.e. four times. You will notice that only in two windows you will see that application is processing. Until this two are not finished, any other is started.

Advertisements

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 )

Twitter picture

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

Facebook photo

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

Google+ photo

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

Connecting to %s