Example # 01: Without Lock Construct
Let’s get started with this article’s first example for lock usage in C#. So, we have to make a C# code structure first. Without the C# standard code structure, our code won’t work. Thus, you need to start it with the use of the “System” library specified by the keyword “using” in the code. As we have to work on threads, we need to specify the Threading namespace of the System library via the “using” keyword.
Both libraries are necessary for the implementation of lock and threads in our examples in this article. After this, we have initialized a simple “Test” class in the C# code. You can also define a namespace before the class but it is not necessary here. The class “Test” contains a total of 2 functions. One is a user-defined function named “show()” and the other is the Main() function of C# that is also an executor function in C# codes. The execution process starts from the Main() method of this program. We have been using the “Thread” class of the “Threading” namespace for the creation of two new thread objects t1 and t1 with the help of a “new” keyword.
Within the Thread creation, we have used the “show” function in the arguments of “Thread” to make it a thread function. As we have created 2 threads, it means the show() function will be used 2 times in the code as thread 1 and thread 2 respectively. This is just a thread creation and not its execution. To execute the thread, we need to use the “Start” function from the Threading class namespace. So, the object “t1” of thread 1 has been used to call the “Start” function to execute the thread function “show”. After the first thread, the second thread t2 will execute the “show” method using the same start function. Now, when a thread has been started, the show() function will be executed by using its “for” loop for up to 5 iterations. Until the loop is executed, it will continue to execute its “Console.WriteLine()” function statement to display the iteration number using the iteration variable “I”. After every iteration, the Thread will get a sleep of 3 seconds by using the “Sleep” function of C# here. The same will be repeated when a second thread gets started. Now, as we have been using threads to execute the “show” function, it is not sure that it will execute it in a manner where . thread 1 first and then thread 2. Let’s save our code to see its result.
We need C# compiler and runtime environment commands to compile and execute our codes. We have already installed both. Thus, we have used the C# “mcs” command used as the C# compiler to compile this newly made code. The compilation returns nothing but generates a new “exe” file in the same current folder i.e. successful.
So, we have executed this “exe” file for the C# code with the C#’s “mono” runtime command. As both the threads were started in the main() function, so they continue to execute the show() function one after another on each iteration. This means, that one thread was taking the resources from the other thread while the first one didn’t even complete its execution fully. This can also cause deadlock.
Example # 02: With Lock Construct
To prevent the threads to execute at the same time while the resources are being shared or requested, we need to use the “lock” construct in the C# code. The lock construct will assure, not allow any other thread to get resources currently used by the currently running process until it completes its execution. This may work on the priority rule or . first come, first served. To use the “lock” construct, we have to create an object for lock using the “object” class of C#.
This object must be of static read-only type. You can name it anything you wish. The creation of a lock object assures that a lock is created and not applied to some parts of the code. We have named it “stop”. Now, we need to create a construct with its keyword “lock” and specify the lock name in its arguments as “stop” within the “show” function. As the show() function is our thread, we have to put its implementation within the “lock” construct (i.e. the piece of code we want to restrict access to.) Now, our code is ready as the lock has been applied to the piece of code within the thread function. Save this updated code and execute it to see its result.
We have compiled this updated code on our Ubuntu terminal and executed its “exe” file after that. This time, the whole “show” function has been executed fully (i.e. “for” loop is completed.) This is because both times when a thread is started with the “Start” function, the “stop” lock construct locked the show() function code until the first thread completed its execution. After that, this happened to thread 2 as well. Therefore, our output is smooth.
The above-shown output will display without any pause and in a second on your screen. This will not let you see how an iterations work one after another when there is no delay in the execution while using a lock. Let’s update the “show” function in the same code and add the Sleep function in it taking 2 seconds of sleep after the execution of Console.WriteLine() function statement while iterating. Save this code with Ctrl+S, close the file and open the shell.
After compiling the code file, we have executed its “exe” file on the shell. The code starts executing its threads. The first thread “show” started while sleeping for 2 seconds after each iteration as shown below.
After the first thread “show” completes its execution, the lock released the access to the show function and thread 2 has been acquired it for execution.
Conclusion:
This article contains details about the Lock construct in C#. We have discussed our first example without using the “lock” construct and got an output with the random and unordered execution of a thread function. We have discussed the causes of this unordered execution of the thread as well. After that, we discussed an example with the use of the “lock” construct and got an output with a random manner of thread execution.