Subj : Re: recursive mutexes To : comp.programming.threads From : doug Date : Mon May 16 2005 04:04 pm "doug" wrote in message news:ds2ie.56042$a9.54345@fe3.news.blueyonder.co.uk... > > "Uenal Mutlu" <520001085531-0001@t-online.de> wrote in message > news:d69n7p$on9$04$1@news.t-online.com... >> "doug" wrote >>> >>> > You seem to not understand what I'm talking about. >>> > Do you understand this fact: "Recursive locking is defined for the >>> > current >>> > lock owning thread only"? >>> > Since you already have the lock you can do what ever you want since >>> > nobody >>> > else can change anything, but you can do! You simply increment it in >>> > Lock() >>> > and decrement it in Unlock(). Because it is safe because you already >>> > have >>> > it locked. >>> > >>> Think carefully. How is this possible? >> >> It is really basic stuff. Ask yourself how you would extend a >> non-recursive >> locking method to make it recursive? Recursivity starts with the 2nd >> Lock() >> call on the same object within the same thread, true? So, after the 1st >> you >> already have the lock, don't you? From then on just use a simple >> unprotected counter. >> It is intended for the current _lock owning thread_ only. It is >> irrelevant for all >> other threads because they don't have the lock. >> Let me know if this makes sense to you. >> > > You're missing the point of the question. If you have the lock, yes, you > can increment a counter. But you need to check if you own the lock first, > don't you? > > Your description above sounds like you're saying: > - use a lock for the first time you grab the counter > - use a counter thereafter. > But then your thread needs to know if already owns the lock. So this > isn't a recursive semaphore at all. > > Let's start again. Here is some pseudocode for a recursive Lock() > routine. A recursive lock consists of a mutex (lock control), a signal var > (condivar), a counter, and a thread identifier. > > Lock() > { > acquire_lock_control > if (lock.owner == me) > } > lock.counter++; > } > else > { > while (lock.counter > 0) > { > release_lock_control > wait_for_condivar ^^^ Sorry, the above two lines were supposed to be on the same line, editor folded them for me. It's supposed be be an atomic release-and-wait (e.g. pthreads pthread_cond_wait) > acquire_lock_control > } > lock.counter = 1; > lock.owner = me; > } > release_lock_control > } > > The above is portable, and SMP safe. > > Can you write us a recursive Lock() using psuedocode that shows what you > mean? The people reading this don't believe it can be done without > syncronisation (i.e. without those acquire/release_lock_control calls). > > > >>> It is possible if you store 'have I got this lock?' in thread local >>> storage. >>> So yes, by keeping a counter here, you don't need a memory barrier in >>> recursive Lock()/Unlock() *. However, when you find that you don't have >>> the >>> semaphore, you still need synchronisation between threads so that the >>> sema4 >>> is acquired safely. >>> What you've ended up doing here is accessing TLS for *every* acquire - >>> thus >>> making the common case of 'semaphore not acquired' slower. >>> >>> (* not true on certain SMP architectures. Without a memory barrier in >>> Lock()/Unlock(), a thread rescheduled on a different CPU may mis-read >>> the >>> recursive counter (depending on how TLS is implemented).) >> >> I think I now know what the reason of these misunderstandings are: >> You and some others seem to see a lock as a property of a thread, >> and by this you do "lock the thread". I on the other hand see a lock as >> a property of the shared object. >> I don't use any TLS, I use just the usual sharing mechanism of threads; >> ie. all objects in a program can be accessed by all threads. >> By this, I put locks on objects, not threads. >> Each such shared object has its own mutex, and not one mutex per thread, >> and of course also not one mutex for all threads (which IMO is nonsense). >> >> > No, I think of a lock as related to one or more pieces of data, not a > thread. Threads acquire the lock to access the data. Recursive locks, > IMO, are used to 'convenience' of coding, where it's easier and/or faster > to use a recursive lock than get your locking design completely correct. > If you're writing an API, recursive locks are a bad idea. If you're > writing a self-contained piece of code and maintainability isn't the > be-all-and-end-all, recursive locks are acceptable. > > The TLS was an idea here to implement recursive locking without > syncronisation when you already own the sema4, but as I pointed out, it a) > won't work on all SMP machines, and b) will run slower. > > Again, you've not actually answered any of my questions. You've pointed > out that I'm wrong, and you're right, but not why. > .