Subj : Re: Deadlock Calculator To : comp.programming.threads From : David Schwartz Date : Sun May 15 2005 12:52 pm "Uenal Mutlu" <520001085531-0001@t-online.de> wrote in message news:d67cb5$l8u$01$1@news.t-online.com... >> I could not disagree more strongly. A deadlock is far preferable to >> continuing erroneous operation. > The point is: if you use a recursive locking method then you > cannot deadlock yourself. Don't you agree with this? Yes, however it greatly increases the risk of deadlocking with another thread or of letting serious programming bugs slip through. >> But that's just the thing, you must not do this. You cannot >> manipulate >> something sanely without knowing already whether or not you have a lock >> on >> it. > I don't think you are beginner in thread programming, but I have > the feeling you just do so. Above I said "just lock it yourself and > proceed" > Of course you ("you" here means _the_current_thread_) cannot proceed > if you don't get the lock, ie. if the lock was done in an another thread; > you will > have to wait (which usually happens inside the Lock() function). > You must think of the "current thread" point of view and in your code > concentrate yourself (the app logic) only on that fact only, you (the > current thread) > don't need to, and mostly also can't, know what other threads are doing. I have no idea how you think this is a response to what I wrote. Sane code must always know what locks it holds (at its own level in the locking hierarchy or lower). Period. >> Ask yourself this -- why do threads lock things and when do they >> unlock >> them? You lock things so you can pass through intermediate states that >> are >> not valid for other threads to see, and you unlock things when you have >> returned them to a valid state. For example, you lock a linked list while >> you add an object to it, because during the add, the linked list passes >> through an inconsistent state. >> >> If the state is consistent, you should release the lock. If the state >> is >> inconsistent, you should not call a function that expects the state to be >> consistent. > > Very true. So then how can you have a function that operates on X that doesn't care whether X is in a consistent or inconsistent state? >> There is also the serious problem of the semantic ambiguity of the >> 'unlock' function. Does it actually unlock the mutex or not? It is easy >> to >> write code that calls 'unlock' and then assumes the mutex is unlocked. >> With >> recursive mutexes, all this code breaks. > A recursive locking method unlocks the lock when the lock counter > is decremented to 0 (done in Unlock()). If it is >0 then the current > thread still has the lock. Unlock() just decrements the lock counter. Right, so it might *not* unlock the object. How natural is it to write code like this: x.Lock(); /* some stuff */ x.Unlock(); /* some stuff that assumes x is unlocked */ This is *broken* if the lock is recursive. > Since only one thread can own (ie. lock) an object, all other > threads (except the current lock owning thread) must wait until the > lock counter becomes 0 again. That's the logic of recursive locking. > Recursive locking is defined for the current "lock owning thread" only. > I would suggest you inform yourself about how CriticalSection of Win32 > works. It's a good example for recursive locking. I'm using similar > logic but mine is at least twice faster. There is plenty of information > available on the net, just google. This in no way responds to what I'm saying. I understand precisely what recurisve and non-recursive locks are. > For example Andrei Alexandrescu (the author of "Modern C++ Design") writes > in > one of his articles (http://www.informit.com/articles/article.asp?p=25298, > page 4): > <<<< > - "Your mutex implementation might support the so-called recursive mutex > semantics. > This means that the same thread can lock the same mutex several times > successfully. > In this case, the implementation works but has a performance overhead due > to > unnecessary locking. [...]" > - "Your mutex implementation might not support recursive locking, which > means > that as soon as you try to acquire it the second time, it blocks - so the > ATMWithdrawal > function enters the dreaded deadlock." > <<<< > The "performance overhead due to unnecessary locking" for recursive > locking > is neglectable if Lock() and Unlock() are carefully designed and > implemented; > Unfortunately the above mentioned CriticalSection of Win32 is a very bad > (slow) > implementation of recursive locking. Since I never complained about performance overhead, I have no idea why you think this is responsive to my criticisms. DS .