I work with multethreading bug. Now I see that for some reason lock isn't executed even once but is locked. I have the next class:
public sealed class Foo
{
private readonly object _lock = new object();
private static ulong _inCnt = 0;
public void SomeMethod(ulong poo)
{
lock (_lock)
{
_inCnt++;
... [some code]
}
}
}
I paused all threads in the VS, inspected all of them and see that there is only one thread in the SomeMethod
and it is waiting for lock (_lock)
to be freed (_inCnt = 0)
.
I resumed threads, waited for a while, paused threads and see the same picture, the same (and only one) thread is still waiting for the lock (_lock)
in SomeMethod
and _inCnt
is zero!
But it will be one or more if lock will be ever entred(_inCnt++
is the first line after lock (_lock)
no exception can happens, we don't abort threads). How can it be zero and lock is locked?
Action: Look at the trace file to see the transactions and resources involved. Retry if necessary. There are several causes for this error: Too high activity - Re-running the job during a less busy period can fix this ORA-00060 deadlock error.
LOCK IN SHARE MODE ), try using a lower isolation level such as READ COMMITTED . When modifying multiple tables within a transaction, or different sets of rows in the same table, do those operations in a consistent order each time. Then transactions form well-defined queues and do not deadlock.
If all of your assumptions are correct, and you are really sure that there never was an unexpected thread abort, then you have to consider GC heap data corruption. The field in System.Object that stores the lock state is fairly vulnerable, it is the very first field in the object. So even a modest buffer overrun in pinvoked native code is liable to overwrite that field and make the CLR think that the lock is held.
Assumptions are however the mother of undebuggable problems and unanswerable questions. Best to check them, it is actually debuggable. I'll assume 32-bit code execution. Use Debug + QuickWatch and type &_lock
. That gives you the address of the object reference. Switch to Debug + Windows + Memory + Memory1 and type the address you got. Right-click the window and select "4-byte integer". You'll now see the address of the object, where it is stored in the GC heap. Subtract 4 from that number and type the result in the Address box. You now see the field that stores the lock state. It is 0 if the lock isn't held, if it is held then it contains the Thread.ManagedId of the thread that owns the lock. You can correlate that to the Debug + Windows + Threads window.
Three basic scenarios:
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