Forum > General
How to debug critical sections? (equal use of Enter and Leave)
piola:
Hello,
in my program, I have hundreds of getters and setters like this:
--- Code: Pascal [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---function TGameSession.GetX;begin FLock.Enter; // type(FLock) = SyncObjs.TCriticalSection try ... do something ... finally FLock.Leave; end;end;
Occasionally I get deadlocks. I'm 99% sure that they are due to a mistake in Enter/Leave. I already found some occurrences where I accidentally used FLock.Enter instead of FLock.Leave. I have already created a descendent class of TCriticalSection which informs me if I use more Leaves than Enters.
However, I have no idea how to handle the other round way where more Enters than Leaves are used.
Someone sketched an idea how to check for proper usage of critical sections but I can't quite figure out how to implement his idea.
If anyone pointed me into the right direction, this would be a valuable help.
PS: Checking for "lock count = 0" at the beginning of Enter won't work because the critical section is sometimes part of a chain of multiple nested calls.
I can store the current lock count within Enter. What I need is some kind of automatism that gets called whenever the function or procedure is being left because that's the only point where I can check the correctness of the lock count for sure.
Martin_fr:
IF it in "only" double enter/leave....
You could use some logging, with indent.
Then if you log like
--- Code: Text [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---->Enter called by "foo"-->Enter called by "bar"--<Leave called by You would see, where it becomes unbalanced. With too many enters the indent will grow.
You do need to log from where it was called. Then you can count
- how often each caller did enter,
- and how often each caller did leave
You can do that without the indent too...
But to many Enter will not Deadlock.
They will just lock all other threads. The thread that did (over-)enter will keep going.
Deadlocks often happen due to: Wrong lock order.
If you have more than one lock (more than one critical section object.
And you have sometimes:
Lock1.Enter;
Lock2.Enter;
and other times
Lock2.Enter;
Lock1.Enter;
Then you can get
--- Code: Text [+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i < x.length; i++) { x[i].style.maxHeight='none'; x[i].style.height = Math.min(x[i].clientHeight+15,306)+'px'; x[i].style.resize = "vertical";}};} ---Thread-1: Lock1.Enter;Thread-2: Lock2.Enter;Thread-2: Lock1.Enter; // wait....Thread-1: Lock2.Enter; // wait..., and since Thread2 waits for Lock1, it wont ever become available
All locks must always enter in the same order.
In the above example, you could in Lock1 (when it is entered non-nested) add a check, that lock2 has not been entered (by the same thread).
Using "threadvar" you can for each lock have a variable that counts, if that lock has been entered by the current thread.
If you are on Linux, there is a great tool called valgrind.
It has 2 very similar tools to analyse your threaded code.
https://valgrind.org/docs/manual/hg-manual.html
https://valgrind.org/docs/manual/drd-manual.html
However, reading and understanding the output of those 2 tools requires time. (And googling).
And, it requires to filter out a lot of false positives.
Also, it does NOT tell you when you enter to often. It can tell you when you Leave to often.
And it can tell you, when you get the order mixed up.
piola:
Thanks for your suggestion. I tried that (with indents) but because I needed the name of the calling method, thus calling BackTraceStrFunc each time, this extremely slowed down program execution.
I ended up writing a small tool which reads the source code files and performs some checks about the correct usage of .Enter and .Leave. And it found 2 occurrences! Hopefully all :)
MarkMLl:
I echo everything that Martin says, and in addition suggest that (a) you reimplement the critical section object (or whatever) with a counter so that you can trap multiple-entry with an assertion, and (b) that in all cases you have a "backdoor" so that where you /know/ that it's safe you can bypass the lock/release.
MarkMLl
piola:
The problem is not entering (I can track this quite well) but leaving. Or better say: forgotten to leave. This happens from time to time because I always type the "TRY FINALLY END" en bloc and add the parts between TRY and FINALLY and between FINALLY and END later. And sometimes I forget the latter -> missing FLock.Leave.
But anyway, thanks for all your help.
Navigation
[0] Message Index
[#] Next page