Especially for asyncronous programming, sometimes we need to lock critical parts of program, therefore we can prevent concurrent executions to be occurred on some data.
You already know the basic lock example, using static object, etc.:
static object LockObject = new object();public void testMethod(){
lock(LockObject){
/*
... some algorithm..
*/
}
}
It seems naive, simple locking solution to prevent concurrent executions on a critical part of program. However, it is not recommended to use lock as simple as shown like in the above code block. Since, multiple threads may be blocked at the beginning of lock block and are forced to wait the thread, which is entered the lock body, is needed to exit the lock body. What would happen if the execution of critical part needs very long time? Many threads are blocked at the beginnging of lock part and the number of usable threads in the thread-pool will decrease, so for some another tasks there will be no available threads to be assinged.
There are non-blocking approaches for these situations. I try to give simple and practicle solution. Lets look at the example below:
static bool CheckLockIsInUse = false;
static object LockObject = new object();public void testMethod(){
if(!CheckLockIsInUse){
lock(LockObject){
CheckLockIsInUse = true;
/* ... some algorith... */
CheckLockIsInUse = false;
}
}
}
Now, it is better. We can make improvement also:
static bool CheckLockIsInUse = false;
static object LockObject = new object();public void testMethod(){
if(CheckLockIsInUse){
return;
}
lock(LockObject){
CheckLockIsInUse = true;
/* ... some algorith... */
CheckLockIsInUse = false;
}
}
}
Even, there can be done another improvement:
static bool CheckLockIsInUse = false;
static object LockObject = new object();public void testMethod(){
if(CheckLockIsInUse){
return;
}
lock(LockObject){
if(CheckLockIsInUse){
return;
}
CheckLockIsInUse = true;
}//end of lock /*... some algorithm... */
CheckLockIsInUse = false;}
The last code block is the best way to implement practical and coincise locking. Lock is used only to set boolean variable’s value, algorithm body is exited from inside of lock body. A little amount of threads will be blocked at the beginning of lock and immediately are freed and inside of lock body, by boolean variable other threads cannot enter the critical part of the program.
Moreover, when we use lock, this lock statement is converted into try-finally block by compiler, and Monitor class is used to manage locking mechanism. You can find more descriptions here:
https://docs.microsoft.com/en-us/dotnet/api/system.threading.monitor?view=netcore-3.1
In another post I will share selective lock mechanism example by using static dictionary.