A deadlock is state in which an application locks up because of the multiple processes are waiting for each other to finish. Basically, this situation takes place in multithreading software in which a shared resource is used by first thread and second thread is waiting for the access to the same resource, at the same time the first thread is waiting for the resource which is used by the second resource so that the each thread is waiting for each other to finish its execution and release the required resource.
There are the four conditions which are necessary for a deadlock to occur:
1. A limited number of a shared resource. In the case of C# monitor, this limited number is one, since a monitor is a mutual-exclusion lock i.e. only one thread can own a monitor at a time.
2. The capacity to hold an access on one resource and requesting the another resource. In C#, this is corresponding to locking on one object and then locking on another before releasing the first lock.
3. No preemption capability. In C#, one thread will not push another thread to release a lock.
4. A circular wait condition. In C#, a multiple threads create a cycle in which each thread is waiting for another other thread to free an acquired resource.
Let's take an example for more explanation about how the deadlock occurs. We assume the following sequence of events:
1. We have thread t1 which acquires an access on resource R1.
2. We have thread t2 which acquires an access on resource R2.
3. When thread t1 try to acquire an access on resource R1 which is already hold by thread t2 so that thread t1 needs to wait until resource R2 is released by the thread t2. At this situation, both threads are waiting and will never acquire their required resources.
See the below C# code to illustrate the deadlock condition: