On 04.10.2006, at 18:44, Stephen Deasey wrote:


OK. I can accept that. Still, you put this into frequently
called procedure and there you go (literals are freed AFAIK,
when procedure scope is exited): again you have global locking.


I'm not sure what you're saying here. What is freed, and when?


The literal object "themutex" is gone after procedure exits
AFAIK. This MIGHT need to be double-checked though as I'm
not 100% sure if the literals get garbage collected at that
point OR at interp teardown.



Right. But why would you ever do this? This was a corner case example
I gave to show that it *could* happen, if you tried real hard and
looked at it funny, but you wouldn't actually do this, right?

Correct.



Unlike with handles
where you get the "real thing" immediately and need not global
lock.


In the case of the thread objects this is the case, but they are
special (or weird). The internal rep of a thread object (mutex, cond
var etc.) is a serialised C pointer. Given the string you can
re-create the pointer (and if you try hard enough you can create an
invalid pointer and crash the server, hence weird).

But for handles in general, such as nsproxy, this is not the case.

Remember, if you can refer to thread objects by name then you don't
*need* to put the name in an nsv array, for example. And if you do,
ns_mutex create does in fact still return a handle.

BUT: to be able to refer them by name I need a lookup table.
And if this is to be thread-wide I need to lock that table globally.



Keeping the handles "away" from the user, means you need to manage
handles yourself because the underlying C code needs handles/ pointers. Every time you do that, you need to lock. In this case the global lock.


But you don't. That's the point. If this isn't the case, then I've
done something wrong and the code needs to be reverted.

You don't?? You do!

 ns_mutex create

returns handle. But I can say:

  ns_mutex lock junklock

and it will *hide* a newly created mutex and tag it with
a "junkmutex" in a thread-wide table. There you go.
The user never "see's" that real mutex handle. He knows
only "junklock". With some object tricks you "remember"
the real handle  so to avoid lookup in a locked table.
But when this shimmers away, you're out of bussiness.

OTOH, when I say

  set mutexhandle [ns_mutex create]

I can do whatever I want with mutexhandle, it will always point to
that damn mutex. I need not do some other lookup in addition.
I can put it into nsv, transfer it over network back to myself...

Thats what I mean by removing the handle from users. If you
do that you need to do more, introduce more locks etc.
Nothing is for free...




So, nothing is for free. By allowing the tcl programmer some freedom,
you charge him with some performance/concurrency.

The best illustration:

lexxsrv:nscp 7> ns_mutex unlock themutex
Connection closed by foreign host.

Here no check is done: you get a core. But if the themutex was
locked before, all would be fine.


I guess this is a good example of trade offs -- performance over
safety. But it's not a good example of the differences between names
and handles, because you can do exactly the same thing:

    % set m [ns_mutex create]
    t0xfd3dd9 a0xa654800 ns:mutex
    % ns_mutex unlock $m

The trade off here is balanced, you can have one thing (safety) or you
can have the other (performance). Your choice. For both handles and
names.

On the other hand, the choice between names and handles is not
balanced. Assuming names actually work (you've sort of said they don't
above), they are equally as fast. So the choice is fast and easy or
fast and hard.

Fast and easy, please!

There's also the question of whether names allow the same kind of
expressive power as handles, in the nsproxy case for example. I think
they are, but that's another thread.

Ah... the handle is an address of the "thing". The name is a tag.
You can tag the same address with several names but only the address
matters, as this is now the lower bits are working. So, when you
have a name of a "thing" you need a table to associate it with
an address in order to find/use it. Right?

If yes, then you need to protect accesses to that table when the
name you use refers to some thread-wide thing. Right?

When you use handles DIRECTLY, the implementation is normally
responsible to make a as-fast-as-possble transformation
to get the thing "address":

   t0xfd3dd9 a0xa654800 ns:mutex

that 0x nubmers is actually the hidden address of the mutex.

What I say is: everytime you make something "nicer" or "easier"
to use, you need to do more work, potentially reducing performance
or concurrency or scalability. This case of tagging thread sync
primitives with names and using the names instead of their handles
is an example. I do not say that what you've done is bad. Actually
it is the best one can do. BUT: it costs concurrency and people
must know that it might be unpredictable and dependent on some
hidden implicit object behaviour.

Bottom line: I do not object. I find it good in any way. It is just
important to know that one might come into concurrency issues at that
point. And it is not always 100% predictable unless you read thru the
lines.



Reply via email to