I've read several articles and posts that say that lock(this)
, lock(typeof(MyType))
, lock("a string")
are all bad practice because another thread could lock on the same key and cause a deadlock. In order to understand this problem, I was trying to create some sample code to illustrate the deadlock but have been unable to wrap my head around this.
Can someone write a concise bit of code that illustrates this classic problem? Please keep it short, I can digest code in smaller chunks only.
Edit: I think lassevk sums it up well; that the real problem is that you have lost control over your locks. Once that happens, you cannot control the order the locks are called, and you are allowing a potential deadlock situation.
lock(this)
, lock(typeof(MyType))
, etc all are situations where you have chosen a lock that is impossible to control.
Deadlock occurs when multiple threads need the same locks but obtain them in different order. A Java multithreaded program may suffer from the deadlock condition because the synchronized keyword causes the executing thread to block while waiting for the lock, or monitor, associated with the specified object.
Deadlock in Java is a condition where two or more threads are blocked forever, waiting for each other. This usually happens when multiple threads need the same locks but obtain them in different orders. Multithreaded Programming in Java suffers from the deadlock situation because of the synchronized keyword.
For example, a computer has three USB drives and three processes. Each of the three processes able to holds one of the USB drives. So, when each process requests another drive, the three processes will have the deadlock situation as each process will be waiting for the USB drive to release, which is currently in use.
A deadlock will only occur if you have more than one lock. You need a situation where both threads hold a resource that the other needs (which means there has to be a least two resources, and the two threads have to attempt to acquire them in a different order)
So a simple example:
// thread 1 lock(typeof(int)) { Thread.Sleep(1000); lock(typeof(float)) { Console.WriteLine("Thread 1 got both locks"); } } // thread 2 lock(typeof(float)) { Thread.Sleep(1000); lock(typeof(int)) { Console.WriteLine("Thread 2 got both locks"); } }
Assuming both threads are started within a second of each others, they will both have time to grab the first lock before anyone gets to the inner lock. Without the Sleep() call, one of the threads would most likely have time to get and release both locks before the other thread even got started.
The idea is that you should never lock on something you cannot control who has access to.
Type objects are singletons visible to every .net piece of code and you cannot control who locks on your "this" object from the outside.
Same thing is for strings: since strings are immutable, the framework keeps just one instance of "hard coded" strings and puts them in a pool (the string is said to be interned), if you write two times in your code the string "hello", you will always get the same abject.
Consider the following example: you wrote just Thread1 in your super private call, while Thread2 is called by some library you are using in a background thread...
void Thread1() { lock (typeof(int)) { Thread.Sleep(1000); lock (typeof(long)) // do something } } void Thread2() { lock (typeof(long)) { Thread.Sleep(1000); lock (typeof(int)) // do something } }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With