On 10/4/06, Zoran Vasiljevic <[EMAIL PROTECTED]> wrote:
On 04.10.2006, at 11:24, Zoran Vasiljevic wrote: > I think I see where the problem is and will fix that now. I've fixed that but this opens another discussion. Basically you wanted to avoid using handles. Then you said, OK, I can use string names and turn them to handles on as-needed basis by looking them up in an internal table. Everytime this lookup happens I need to global lock the table then lookup the (whatever)handle using it string name. To avoid that global lock, you change/update the object holding the string rep with the calculated handle and you count on the fact that next usage of the same object will avoid having to to the (costly) lookup.
Right. And the reason the handle name doesn't have to be looked up again because we cheat -- the mutexes associated with the handle names live forever. You can't delete or reassign them. So if you ever find a pointer to a mutex in one of these handle names, it's valid.
Did you think about such uses: ns_mutex lock themutex while {} { ns_cond wait thecond themutex } ns_mutex unlock themutex because here EVERY time you will have to lock the global lock to get the handle of the "thing", as the "trick" to save it in the object will not work! The "themutex" or "thecond" could/will always be different objects if used this way, so there is no gain.
Hmm... I think this does work. Here's how I read it: There are 3 string objects with the value "themutex" in the above code. The first time the code runs, there will be 3 global look ups in the hash table of mutex names to convert the name "themutex" to a pointer to an actual mutex. On the first line, in the call to "ns_mutex lock themutex", the last argument is just a Tcl string object so we have to look up the name in the mutex hash table. The name doesn't exist, so a new mutex is allocated, put in the hash table, and a pointer to it is stored in the Tcl object. The Tcl object is marked as an Address obj type (it's string rep is not invalidated, we just change the type). In the call to ns_cond and the last call to ns_mutex, "themutex" is also just a Tcl string object. So again the mutex hash table has to be consulted. This time the mutex exists however, so we simply change the string object to an Address type and store a pointer to the existing mutex in it. There are 3 individual Tcl objects, each with the string representation "themutex". Each now points to exactly the same mutex in memory. The second time the code is run, the 3 "themutex" objects retain their type (Address), so we don't have to look up the name in the mutex hash table as a pointer to the mutex is stored in the Tcl object itself. We get access to the mutex with a simple pointer dereference. So, the premise is that the code will be executed more than once. The first time will be 'slow', but after that there is no locking at all to convert the name to an actual mutex. And it works specifically in the above case because mutex objects are seperate from Tcl objects which point to them.
If one however does: set m themutex set t thecond ns_mutex lock $m while {} { ns_cond wait $c $m } ns_mutex unlock $m it WILL work. But how are you going to convey this information to the Tcl programmer??? He's implicitly serializing his app at the place he does not expect (lookup of the internal hash table).
Actually, the above might NOT work... :-) In the above code, $m is a single Tcl string object with the value "themutex" and, after the first call to "ns_mutex lock $m", we convert it to a an Address type and point it at a mutex. There is a single Tcl object pointing to a single mutex, where as in the original code there were 3 Tcl objects pointing to a single mutex. There will be a single look up in the mutex hash table, where as in the original code there will be 3. But only on the first time the code is run. The while loop will be 'efficient' because the underlying mutex object is just a pointer dereference away. However, what if the whole code block was run in a loop? At the bottom of the loop, $m is an Address type pointing to our mutex. At the top of the loop $m is reset: set m themutex The value of the literal "themutex" Tcl string object is copied and used as the new value of $m. Because the string representation of $m has changed (even if the actual text is literaly the same, there is no checking for this), the internal representation is invalidated. i.e. it is no longer an Address type. So at the top of the loop we again have to convert m to an Address type be looking up the name in the mutex hash table. The mutex will exist in the hash table, but we need to get a pointer to it. Any operation which looses the type information will break the caching of the mutex pointer in the object. So, passing the name through an nsv array or cache will strip the type info. But I'm having a hard time coming up with real world scenarios where that might happen...