Part 93 Protecting shared resources from concurrent access in multithreading

18
7



Text version of the video

Slides

All C# Text Articles

All C# Slides

All Dot Net and SQL Server Tutorials

In this video we will discuss,
1. What happens if shared resources are not protected from concurrent access in multithreaded program
2. How to protect shared resources from concurrent access

What happens if shared resources are not protected from concurrent access in multithreaded program
The output or behaviour of the program can become inconsistent if the shared resources are not protected from concurrent access in multithreaded program. Let us understand this with an example.

using System;
class Program
{
static int Total = 0;
public static void Main()
{
AddOneMillion();
AddOneMillion();
AddOneMillion();
Console.WriteLine(“Total = ” + Total);
}

public static void AddOneMillion()
{
for (int i = 1; i [= 1000000; i++)
{
Total++;
}
}
}

The above program is a single-threaded program. In the Main() method, AddOneMillion() method is called 3 times, and it updates the Total field correctly as expected, and finally prints the correct total i.e 3000000.

Now, let’s rewrite the program using multiple threads.
using System;
using System.Threading;
class Program
{
static int Total = 0;
public static void Main()
{
Thread thread1 = new Thread(Program.AddOneMillion);
Thread thread2 = new Thread(Program.AddOneMillion);
Thread thread3 = new Thread(Program.AddOneMillion);

thread1.Start();
thread2.Start();
thread3.Start();

thread1.Join();
thread2.Join();
thread3.Join();

Console.WriteLine(“Total = ” + Total);
}

public static void AddOneMillion()
{
for (int i = 1; i [= 1000000; i++)
{
Total++;
}
}
}

Every time we run the above program, we get a different output. The inconsistent output is because the Total field which is a shared resource is not protected from concurrent access by multiple threads. The operator ++ is not thread safe. There are several ways to fix this. Let’s explore 2 of the options.

Using Interlocked.Increment() method: Modify AddOneMillion() method as shown below. The Interlocked.Increment() Method, increments a specified variable and stores the result, as an atomic operation
public static void AddOneMillion()
{
for (int i = 1; i [= 1000000; i++)
{
Interlocked.Increment(ref Total);
}
}

The other option is to use a lock.
static object _lock = new object();

public static void AddOneMillion()
{
for (int i = 1; i [= 1000000; i++)
{
lock (_lock)
{
Total++;
}
}
}

Which option is better?
From a performance perspective using Interlocked class is better over using locking. Locking locks out all the other threads except a single thread to read and increment the Total variable. This will ensure that the Total variable is updated safely. The downside is that since all the other threads are locked out, there is a performance hit.

The Interlocked class can be used with addition/subtraction (increment, decrement, add, etc.) on and int or long field. The Interlocked class has methods for incrementing, decrementing, adding, and reading variables atomically.

The following code prints the time taken in ticks. 1 millisecond consists of 10000 ticks.
public static void Main()
{
Stopwatch stopwatch = Stopwatch.StartNew();
Thread thread1 = new Thread(Program.AddOneMillion);
Thread thread2 = new Thread(Program.AddOneMillion);
Thread thread3 = new Thread(Program.AddOneMillion);

thread1.Start();
thread2.Start();
thread3.Start();

thread1.Join();
thread2.Join();
thread3.Join();

Console.WriteLine(“Total = ” + Total);

stopwatch.Stop();
Console.WriteLine(“Time Taken in Ticks = ” + stopwatch.ElapsedTicks);
}

Please Note: You can use the TimeSpan object to find ticks per second, ticks per millisecond etc.

Nguồn:https://wijstaanvooronzegrondrechten.org/

18 COMMENTS

  1. Question is , WHY during concurrent access, sometimes we get less than 3 million? How can a thread make a mistake in the for loop?

  2. i have a question , how do i make solution not close as soon as i open it ? i used to use Console.Readkey(); at the end but even that fails at times, because it keeps telling me that It is not present withing the class/system or w/e it's called. so i'm kind of stuck

  3. When I tried using interlocked.increment method instead of ++ operator, the performance is greatly affecting. Can anyone explain this. ??

  4. Interesting that the performance gain by allowing all 3 threads to access the method is about 3 times faster than the single-threaded option.
    I suppose it makes sense, but programming tends to make me expect seemingly nonsensical answers, despite their perfectly logical foundation.

  5. more vids venkat.  awesome series.  you should make a series for people like me that have little to no experience programming, and know little about how computers work.. alot of being successful programming is knowing how computers work, and these thread videos are a great example of this.  

  6. Sir, On the lock(_lock) ,  sample, Why is it enough to lock the increments to prevent other threads? I thought the lock should have been on the for loop. I'm thinking that if the current thread goes out of the lock(_lock) and into the for loop, then other threads can sneak into the lock(_lock). Would this be possible?

  7. Dear Kudvenkat ! I really do not know if u have videos about dependency injection in c# ! I really do not understand this subject and the reason is i could not understand it is no real example that i could feel the importance of this topic ! please reply me !

LEAVE A REPLY

Please enter your comment!
Please enter your name here