No, interfaces are completely unrelated to deadlocks. If you have a deadlock then it is, by definition, because synchronized access to a shared resource not slow I/O):
A deadlock is a situation in which two or more competing actions are each waiting for the other to finish, and thus neither ever does.
How to Debug Them?
There can be many causes for a deadlock (of course some conditions - slow I/O, CPU intensive algorithms - may cause a deadlock to appear more often but they're not The Cause).
Most of times it's easy to detect them if you can attach debugger to your application. Pause execution when it's hanged, explore thread list and their stacks you can see if they're waiting on a shared resource.
A very common deadlock scenario is this:
- Thread 1 acquires lock on resource A.
- Thread 2 acquires lock on resource B.
- Thread 1 tries to acquire lock on resource B but it's locked by thread 2 then thread 1 will be suspended (little bit simplified).
- Thread 2 tries to acquire lock on resource A but it's locked by thread 1 then thread 2 will be suspended.
- Both threads are suspended then they can't release locks they acquired. If there isn't a timeout then this condition won't be solved (application, or a part of it, may hang).
Another very common scenario:
- Thread 1 acquires a lock on resource A, (not using, for example,
lock
statement in C# but directly with Monitor.Enter()
or through another synchronization primitive like ReadWriterLockSlim
).
- Execution fails because of an exception. Exception is handled but lock isn't released.
- First time another thread (or same thread if lock supports reentrancy) will try to use same lock then application will hang (because lock has never been released).
This is a code example (very naive lock mechanism, I know):
object _syncRoot = new object();
void ThreadWorker(object state ) {
Monitor.Enter(_syncRoot);
try {
// Do some operation that may fail
// Release lock
Monitor.Exit(_syncRoot);
}
catch (Exception e) {
// Log error
}
}
Fortunately this is pretty easy to avoid (check this answer to see how lock implements monitor).
try {
lock (_syncRoot) {
// Do your job here
}
}
In previous scenario same thread won't be hanged if it'll re-access this lock (but other thread will) but if you're using, for example, a read/write lock then it'll hang (or it'll fail if it doesn't support reentrancy, see this question for other details). This kind of failures may be detected if you use a timeout for your locks (of course this is not always possible). When a lock attempt will timeout your application will detect it and take proper actions (if any, it may even simply abort gracefully).