That's fine so long as you control every single thread which is created
in the system. That sounds like an unlikely situation to me. Can you be
absolutely sure that *no* calls you make to any third-party library or
the framework itself will create any new threads?
If my only concern is to capture debug output generated by my own threads
then it is entirely suitable.
If a third-party
library creates a thread, it may have the same hashcode as an "old"
thread which registered itself, the code won't be able to tell the
difference between this third-party thread and the old thread.
That depends entirely on the requirements. If controlled access from all
possible threads is a requirement then I would use a different mechanism. If
the only threads I need to concern myself with are threads that I have
created and have control over, then my method is entirely suitable. Since
the original question never stated how the debug output was to be generated
we were never working from the same page.
I think you and I are disagreeing because we each had different unstated
requirements.
Yes. I'm talking about uniqueness across the lifetime of the
application, which seems like a much more useful form of uniqueness in
this situation.
How long is the lifetime of your app?
If you want uniqueness across the lifetime of an app then using a weak
reference is questionable. If the app lifetime is measured in months and the
rate of generating new references is high then if you have to retain a weak
reference in order to guarantee uniqueness then you will eventually run the
system out of memory. If that is your requirement I would not use a weak
reference in a hashtable; I would generate a guid and store it in TLS.
If the only requirement is uniqueness during the lifetime of the thread then
all that is required is a number that is unique during the thread's
lifetime, which is much shorter then the potential lifetime of the app. The
runtime has no trouble using the hashcode to determine uniqueness; neither
should our code.
In win32 there were notifications the app would receive whenever a thread
was created or destroyed - there is no such mechanism in dotnet but there
should be. Then we could use whatever mechanism we wanted for all threads
regardless of where they were created.
See above for the reason why your scheme doesn't work unless you
control every thread in the system.
No, it only requires that you control every thread whose output you wanted
to monitor, and that is exactly what I was assuming. Without a complete
statement of requirements we are each free to make different assumptions,
and we did.
Well, it's a slightly more difficult way of doing it, but it's
essentially doing the same thing.
No, it is very different. With TLS the data itself is locked to the object -
with a weak reference there is no such guarantee - it's a reference to an
object which may cease to exist.
Yes, but that's not the only situation in which they're useful.
Correct but in this situation it is not a method I would use.
I wouldn't. That's not how I was proposing to use it. The WeakReference
would effectively serve the same purpose as TLS - it would associate
some extra data with a Thread reference, but without preventing the
Thread object from being garbage collected.
Except that it increases memory pressure on the system. TLS is a far
superior mechanism to use.
But your scheme requires every bit of code which creates a thread to
register - otherwise it can get an old value. My scheme requires only
those threads which are genuinely interested in different behaviour
registering. In what way is your scheme easier?
Not really. It depends more on how output is captured. I usually use my own
logging/capturing classes so I have total control over this. I usually need
some way of setting priorities, levels of output (verbose, terse) etc, and
this requires a finer degree of control. Since threads come and go I usually
have to make a call from within the thread when it initializes to set the
logging controls. Adjusting the knobs is a necessary evil.
If you wanted to trace a transaction through a heavily multi-threaded
environment you would need a different mechanism anyway - you would need to
associate state with each transaction. And if you wanted to track
transactions across process and machine boundaries it's different again.
And I would certainly hope that any field marked with the
ThreadStaticAttribute is automatically cleaned up by the CLR -
otherwise it's a pointless attribute.
Admittedly I can't see it *documented* that the thread-local storage
allocated by it is automatically freed, but then it doesn't document
that you have to manually free it, either.
Do you have any real reason not to trust ThreadStaticAttribute?
I do trust that attribute but that is not the only means of using TLS. It
can be allocated dyncamically - that's the method I was referring to.
It's a different class of bug though. It's a bug of omission rather
than a bug of faulty logic, and
Failing to adhere to a requirement, such as not invoking Dispose on an
object that requires it, is a bug even though it is an omission to invoke a
method call rather then an abuse of a method.
Who says that *you're* creating the thread though? You may not have
created the thread, and may not have control over its use later on, but
still want to register for it to act a particular way in terms of
tracing. Using TLS allows that. Your scheme doesn't.
This goes back to differing assumptions. The original message specifically
mentioned capturing debug output...we then each made different assumptions
about what that meant.
Also, this is a pure out-and-out bug. If you want to pass a handle to some
other code you are supposed to make a duplicate handle to prevent this. It's
similar to COM pointers - you're supposed to AddRef it each time you make a
copy of it.
Then you've missed at least one use of weak references.
True, but it's one use I would never use anyway. I'd use a weak reference as
a weak reference.