Category Archives: Synchronization

ReaderWriterLockSlim – synchronizing threads

ReaderWriterLockSlim is a synchronization mechanism. It allows many threads to read the same resource and the only one resource to write the resource.

Example below is not synchornized. There are four tasks and two of them can update myValue in the same time. It can cause that at the end myValue != 0.

        public void StartWithoutSynchronization()
        {
            int myValue = 0;

            //edits the value
            var taskA = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    myValue++;
                }
            });

            //edits the value
            var taskB = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    myValue--;
                }
            });

            //reads the value
            var taskC = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("C " + myValue);
                }
            });

            //reads the value
            var taskD = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    Console.WriteLine("D " + myValue);
                }
            });

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

            Console.WriteLine(myValue);

            Console.WriteLine("Finished");
        }

The example below is edited to be synchronized using ReaderWriterLockSlim. Now only one task at a time can write.

        public void StartSynchronized()
        {
            var rwLock = new ReaderWriterLockSlim(LockRecursionPolicy.NoRecursion);
            int myValue = 0;

            //edits the value
            var taskA = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    rwLock.EnterWriteLock();
                    myValue++;
                    rwLock.ExitWriteLock();
                }
            });

            //edits the value
            var taskB = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    rwLock.EnterWriteLock();
                    myValue--;
                    rwLock.ExitWriteLock();
                }
            });

            //reads the value
            var taskC = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    rwLock.EnterReadLock();
                    Console.WriteLine("C " + myValue);
                    rwLock.ExitReadLock();
                }
            });

            //reads the value
            var taskD = new Task(() =>
            {
                for (int i = 0; i < 100; i++)
                {
                    rwLock.EnterReadLock();
                    Console.WriteLine("D " + myValue);
                    rwLock.ExitReadLock();
                }
            });

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

            Console.WriteLine(myValue);

            Console.WriteLine("Finished");
        }

Mutex – synchronizing processes

Mutex is a mechanism which allows us to synchronize processes. (see also: semaphore).
Mutex is resource consuming stuff, so avoid it if possible.

Imagine we have an application which writes something into a file. If we run two instances lines in file will be mixed.

        public void WriteToSharedFileWithoutSync()
        {
            StreamWriter oFile = null;
            try
            {
                for (int i = 0; i <= 25; i++)
                {
                    oFile = File.AppendText(@"logger.log");
                    var txt = "Sample line..." + i;
                    oFile.WriteLine(txt);
                    Console.WriteLine(txt);
                    oFile.Flush();
                    oFile.Close();
                    Thread.Sleep(250);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                if (null != oFile)
                {
                    oFile.Close();
                    oFile.Dispose();
                }

                Console.Write("Saving finished.");
            }
        }

Run code above executing two separate instances of the same application to see results.

We can synchronize this two instances using mutex. See example below.

        private Mutex _mutex = new Mutex(false, "991FE2BE-A4DD-47CE-AC9B-C97A908EA560"); //create mutex with unique name somewhere in your application 


        public void WriteToSharedFileWithSync()
        {
            _mutex.WaitOne(); //wait if somebody else is in critical section

            StreamWriter oFile = null;
            try
            {
                for (int i = 0; i <= 25; i++)
                {
                    oFile = File.AppendText(@"logger.log");
                    var txt = "Sample line..." + i;
                    oFile.WriteLine(txt);
                    Console.WriteLine(txt);
                    oFile.Flush();
                    oFile.Close();
                    Thread.Sleep(250);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex);
            }
            finally
            {
                if (null != oFile)
                {
                    oFile.Close();
                    oFile.Dispose();
                }

                _mutex.ReleaseMutex(); //release critical section after writing
                Console.Write("Saving finished.");
            }
        }

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.

Lock, Monitor, Interlocked – synchronizing threads

Imagine we have code with two threads. The first one adds one to shared variable. The other one substracts one from shared variable. Both work in a loop.

public void StartWithoutSynchronization()
{
        int x = 0;	
        //this task adds 1 to X in loop
	var taskPlus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			x = x + 1;
		}
	});

	//this task substracts 1 from X in loop
	var taskMinus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			x = x - 1;
		}
	});

	taskPlus.Start();
	taskMinus.Start();
	Task.WaitAll(taskPlus, taskMinus);

	//when both tasks finish we expect x == 0, 
        //but it's not due to the fact that adding and substracting are not atomic opeartions
	Console.WriteLine("Total value: " + x);
}

After executing the code above you will notice that final result is not 0.
We can fix it in a few simple ways.

Locks allows us to synchronize the threads. We make locks on private objects (to lock in current instance) or private static objects (to lock all instances).

        public void StartSynchronizedWithLock()
        {
            int x = 0;
            var xLock = new object();

            //this task adds 1 to X in loop
            var taskPlus = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    // lock causes that only one thread at a time can have access to code in lock body
                    // notice we have lock on the same object in the other task
                    lock (xLock)
                    {
                        x = x + 1;
                    }
                }
            });

            //this task substracts 1 from X in loop
            var taskMinus = new Task(() =>
            {
                for (int i = 0; i < 100000; i++)
                {
                    // lock causes that only one thread at a time can have access to code in lock body
                    // notice we have lock on the same object in the first task
                    lock (xLock)
                    {
                        x = x - 1;
                    }
                }
            });

            taskPlus.Start();
            taskMinus.Start();
            Task.WaitAll(taskPlus, taskMinus);

            //when both tasks finish we expect x == 0 and result really is 0
            Console.WriteLine("Total value: " + x);
        }

Monitor is analogical mechanism to lock, but with more options to use and longer, more complicated syntax. Monitor additionaly have TryEnter method which informs whether thread can access critical section or not.

public void StartSynchronizedWithMonitor()
{
	int x = 0;
	var xLock = new object();

	//this task adds 1 to X in loop
	var taskPlus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			Monitor.Enter(xLock); //monitor blocks thread if another thread is already in critical section
			try
			{
				x = x + 1;
			}
			finally
			{
				Monitor.Exit(xLock); //lock is released in finally clause
			}
		}
	});

	//this task substracts 1 from X in loop
	var taskMinus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			Monitor.Enter(xLock);
			try
			{
				x = x - 1;
			}
			finally
			{
				Monitor.Exit(xLock);
			}
		}
	});

	taskPlus.Start();
	taskMinus.Start();
	Task.WaitAll(taskPlus, taskMinus);

	//when both tasks finish we expect x == 0 and result really is 0
	Console.WriteLine("Total value: " + x);
}

Interlocked it’s a class which exposes a few atomic methods (i.e. .Increment, .Add, .Exchange).

public void StartSynchronizedWithInterlocked()
{
	//this task adds 1 to X in loop
	var taskPlus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			Interlocked.Add(ref x, 1); // this add operation is atomic
		}
	});

	//this task substracts 1 from X in loop
	var taskMinus = new Task(() =>
	{
		for (int i = 0; i < 100000; i++)
		{
			Interlocked.Add(ref x, -1); // this add operation is atomic
		}
	});

	taskPlus.Start();
	taskMinus.Start();
	Task.WaitAll(taskPlus, taskMinus);

	//when both tasks finish we expect x == 0 and result really is 0
	Console.WriteLine("Total value: " + x);
}

ManualResetEvent – synchronizing threads

ManualResetEvent class allows us to synchronize threads. It’s very similar to AutoResetEvent (see before continuing: AutoResetEvent – synchronizing threads)
The difference is that we need one more thing comparing to AutoResetEvent. ManualResetEvent have one more method – Reset(). It allows us to set non-signaled state (opposite to Set() method).
ManualResetEvent does not set non-signaled state when WaitOne() method is executed (as it happens in AutoResetEvent).

Imagine that we have this familiar code, but with ManualResetEvent instead of AutoResetEvent.

        ManualResetEvent _manualResetEventHi = new ManualResetEvent(true); //initialized to signaled state - will not block thread
        ManualResetEvent _manualResetEventHello = new ManualResetEvent(false); //initialized to non-signaled state - will block thread

        public void StartWithSynchronization()
        {
            //we start both threads in the same time
            SayHiSync();
            SayHelloSync();
        }


        private void SayHiSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _manualResetEventHi.WaitOne();
                    Console.WriteLine($"Hi! ({i} sync)");
                    i++;
                    _manualResetEventHello.Set();
                }
            });
        }

        private void SayHelloSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _manualResetEventHello.WaitOne();
                    Console.WriteLine($"Hello! ({i} sync)");
                    i++;
                    _manualResetEventHi.Set();
                }
            });
        }

It won’t synchronize the threads. We have random order in console. Code below fixes this situation:

        ManualResetEvent _manualResetEventHi = new ManualResetEvent(true); //initialized to signaled state - will not block thread
        ManualResetEvent _manualResetEventHello = new ManualResetEvent(false); //initialized to non-signaled state - will block thread

        public void StartWithSynchronization()
        {
            //we start both threads in the same time
            SayHiSync();
            SayHelloSync();
        }


        private void SayHiSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _manualResetEventHi.WaitOne();
                    Console.WriteLine($"Hi! ({i} sync)");
                    i++;
                    if (i % 2 == 0)
                    {
                        _manualResetEventHi.Reset();
                        _manualResetEventHello.Set();
                    }
                }
            });
        }

        private void SayHelloSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _manualResetEventHello.WaitOne();
                    Console.WriteLine($"Hello! ({i} sync)");
                    i++;
                    if (i % 2 == 0)
                    {
                        _manualResetEventHello.Reset();
                        _manualResetEventHi.Set();
                    }
                }
            });
        }

We have following result in console: Hi – Hi – Hello – Hello – Hi – Hi – Hello – Hello – Hi – Hi – …
It is synchronized again because we added two important lines:
_manualResetEventHi.Reset(); – sets non-signaled thread for the other thread (as it is not done automatically like with AutoResetEvent).
_manualResetEventHello.Reset(); – sets non-signaled thread for the first thread (as it is not done automatically like with AutoResetEvent).

AutoResetEvent – synchronizing threads

AutoResetEvent class allows us to synchronize threads.
There are a few important things to know:
1. Constructor:
If you pass true to the constructor it means that thread which uses this AutoResetEvent is free to go and won’t be blocked (state equal to ‘signaled’). If you pass false – thread will be blocked (‘non-signaled’).

2. WaitOne() method:
It causes that thread checks whether it can go (if signaled – can go; if non-signaled – is blocked and waits here). If it can go it immediately sets state to non-signaled.

3. Set() method:
Sets AutoResetEvent to signaled state – threads won’t be blocked.

No synchronization
Imagine that we have two threads. One prints in loop “Hi!” and the other prints in loop “Hello!”. If we do not synchronize this two threads order of messages is random. See below:

        #region nosync
        public void StartWithoutSynchronization()
        {
            SayHiNoSync();
            SayHelloNoSync();
        }

        private void SayHiNoSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    Console.WriteLine($"Hi! ({i} no sync)");
                    i++;
                }
            });
        }

        private void SayHelloNoSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    Console.WriteLine($"Hello! ({i} no sync)");
                    i++;
                }
            });
        }
        #endregion nosync

resetevent_nosync

Synchronized
Now imagine that we want to have messages in console in following order: “Hi” – “Hello” – “Hi” – “Hello” – “Hi” – “Hello” – …
We can make use of AutoResetEvent. See below:

        #region sync
        AutoResetEvent _autoResetEventHi = new AutoResetEvent(true); //initialized to signaled state - will not block thread
        AutoResetEvent _autoResetEventHello = new AutoResetEvent(false); //initialized to non-signaled state - will block thread


        public void StartWithSynchronization()
        {
            //we start both threads in the same time
            SayHiSync();
            SayHelloSync();
        }


        private void SayHiSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _autoResetEventHi.WaitOne(); //thread checks whether can go or not
                    Console.WriteLine($"Hi! ({i} sync)");
                    i++;
                    _autoResetEventHello.Set(); //sets the other autoResetEvent to signaled state
                }
            });
        }

        private void SayHelloSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _autoResetEventHello.WaitOne(); //thread checks whether can go or not
                    Console.WriteLine($"Hello! ({i} sync)");
                    i++;
                    _autoResetEventHi.Set(); //sets the other autoResetEvent to signaled state
                }
            });
        }
        #endregion sync

resetevent_sync

Explanation:
Both tasks are started in the same time. _autoResetEventHi is initialized not to block the thread. This thread will imediately set state of _autoResetEventHi to non-signaled. _autoResetEventHello is initialized to non-signaled state and will block the thread.
Console will print out “Hi” message. Then this thread will set _autoResetEventHello to signaled state. It will allow the other thread to finish waiting. The other thread sets immediately state of _autoResetEventHello to non-signaled. Console will print out “Hello”.
Then the first thread can again process the loop and unlock the other thread. The other thread is unblocked, processes the message and unlocks the first one… This is how it works.

Synchronized (with defined waiting timespan)
Additional information: WaitOne method accepts parameter (int). It informs how long thread should wait. If you won’t pass this argument it will wait forever (until it is signaled as default value is -1). If you set i.e. 1000 thread will wait (if is blocked) for one second and then continue processing.

Note the code below. I commented out one line end edited one more.

        private void SayHiSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _autoResetEventHi.WaitOne();
                    Console.WriteLine($"Hi! ({i} sync)");
                    i++;
                    //_autoResetEventHello.Set(); //it means _autoResetEventHello will not be signaled at all!
                }
            });
        }

        private void SayHelloSync()
        {
            int i = 0;
            Task.Run(() =>
            {
                while (i < 50)
                {
                    _autoResetEventHello.WaitOne(5000); //it means thread will wait 5 seconds when blocked
                    Console.WriteLine($"Hello! ({i} sync)");
                    i++;
                    _autoResetEventHi.Set();
                }
            });
        }

The final result in console is the same. The difference is that message “Hi” appears immediately and then we wait 5 seconds for “Hello”. Then “Hi” appears immediately again and again we wait 5 seconds for “Hello”…