Smart Resource Locking in C# .Net for Thread Safe Code
Updated 1/8/2012: Removed code formatting to use SyntaxHighlighter and fixed off colors on titles.
So you are into thread safe code and you have begun to lock resources. But the trap that all new programmers sometimes do is to lock the whole class as shown below:
public void DeadlockWaitingToHappen1(string change) { lock (this) { _Resource1 = change; } } public void DeadlockWaitingToHappen2(string change2) { lock (this) { _Resource2 = change2; } }
The problem with the above code, albeit trite due to the example, is that when a thread 1 calls the first method to change resource1, it will effectively block any other thread calling the opposite method to change _resource2.
Because we know that these resources are independent, such locking in the above case is a nuance, in a more advanced state, causes undo wait times for resources, but in a worse case scenario could cause deadlocks in code!
Solution
To get around that what we will do is to lock separate objects. The below code will create mirror object locks and use those to properly lock our different distinct resources.
// This class simulates the use of two different // thread safe resources and how to lock them // for thread safety but not block other // threads getting different resources. public class SmartLocking { private string StrResource1 { get; set; } private string StrResource2 { get; set; } private object _Lock1 = new object(); private object _Lock2 = new object(); public void DoWorkOn1( string change ) { lock (_Lock1) { _Resource1 = change; } } public void DoWorkOn2( string change2 ) { lock (_Lock2) { _Resource2 = change2; } } }
Summary
As you can see we have separate locks, so now thread 1 accessing resource 1 won’t block thread 2 accessing resource 2. Note if the object you are working contains the interface to allow locking and it makes sense to use that resource, then lock it instead of a separate object.
[…] OmegaMan is a moderator on Microsoft’s MSDN forums with over 2000 posts. (Recent Post: Smart Resource Locking in C# .Net for Thread Safe Code) […]
Actually that couldn’t cause a deadlock because there is only a single lock taken. You’re right that it could cause more contention than is strictly necessary, but for a deadlock you need two locks taken in different orders. Below is an example of a deadlock waiting to happen:
class DeadlockWaiting
{
readonly object lock1 = new object();
readonly object lock2 = new object();
public void DoWork1()
{
lock (lock1)
lock (lock2)
// synchronised code
}
public void DoWork2()
{
lock (lock2)
lock (lock1)
// synchronised code
}
}
Here it is possible for DoWork1 to lock lock1, and DoWork2 to lock lock2, and then each method is waiting for the other to release the lock (which will never happen) hence the deadlock.
If there is only one lock, then it will always be released, hence no deadlock.
[…] As a contract Architect/Developer/Programmer in the software industry, OmegaMan creates tools and architects code that never sees the light of day. This blog is a way to transfer some information to the community as a whole. OmegaMan is a moderator on Microsoft’s MSDN forums with over 2000 posts. (Recent Post: Smart Resource Locking in C# .Net for Thread Safe Code) […]
Why not just lock on _Resource1 and _Resource2 instead of creating separate objects. Its cleaner and does the same thing, no?
Yes locking the actual object is cleaner in most cases. This article is targeted to developers who lock the whole object (lock(this)). They may not know that one can lock *other* objects or the objects themselves. Thanks for the thought!
[…] http://www.omegacoder.com […]