I'll document some essential debugging techniques. Start with Debug + Windows + Threads, it shows you a list of all threads that are running in your process. You can hover over the Location column and you'll get a tooltip that shows the stack trace for the thread. That lets you quickly home in on threads that actually are running your code. Double click one of interest, then switch to Debug + Windows + Call Stack to get a more permanent view. This may help you find the thread that has acquired the lock.
Failing that, you can find out what thread owns the lock object. Switch to the thread that is blocked by double-clicking it then use Debug + Windows + Memory + Memory 1. Type "_sync" in the Address box. Right-click the window and select "4-byte Integer". Subtract 4 from the hexadecimal address shown in the upper left corner of the window and type that address in the Address box. Or click the scrollbar up arrow and look at the last value in the first line. That's the Thread.ManagedThreadId of the thread that owns the lock. Beware that this doesn't always work, this field in an object is used for other purposes as well (GetHashCode for example).
Knowing the managed ID of the thread now lets you look in the Debug + Windows + Threads window for the thread. But only on VS2010, earlier versions don't display the managed ID of threads in this window. For those, you'll need to add some tracing code that displays the value of Thread.CurrentThread.ManagedThreadId. Adding tracing code is in general a useful technique to troubleshoot threading problems. It is very risky however, this code alters the timing and may make the threading problem disappear. Many trace listeners also have an implied lock.