[concurrency-interest] Soliciting input about removeAllThreadLocals

David Holmes dholmes@dltech.com.au
Tue, 10 Dec 2002 09:21:59 +1000


This is on the interest list and BCC'ed to the EG.

I'm going to sum up what I think is the position based on what others
have recently said.

The main issues:

- Clearing all threadlocals is necessary to avoid unintentional reuse
of a thread local value.
- Clearing all threadlocals could break existing code by violating
invariants that the code has established.

removeAllThreadLocals is one of those methods that should only be used
at very specific points in a threads life - in this context: when that
thread is actually in a thread pool and is about to execute a new
task. Trying to restrict the method such that it can only be used then
is not straight forward - a security check is necessary but not
sufficient. We can't test something like isAlive() because the pool
thread is always alive.

Defining a special type of resettable thread-local is not really an
option as it relies on third parties doing the right thing. The
problem is that this makes life difficult to the library users, not
the library writers. I'd argue that anyone changing their library to
use resetable threadlocals could probably redesign things such that
they don't care whether the threadlocal gets reset or not.

The real solution here would be a "light-weight" rebirthing mechanism
for threads - such that it gets a new identity and hence will get new
threadlocals anyway because it is for all intents and purposes a "new
thread", we just didn't have to throw away all of the old thread. To
use Josh's used-car analogy we just chiselled in a new ID number :-)

But lets take a step back to see where the problem with not having
removeAllThreadLocals could arise. It is really a narrow set of use
cases in Category 1 of Josh's taxonomy. Not all Category 1 uses are
encapsulated in a a library protocol where correct usage of the
library requires you to invoke a setup method and finally invoke a
cleanup method. In those cases resetting or not makes no difference if
you obey the protocol and if you don't then all bets are off anyway.

The situation where it would be a problem not to reset threadlocals is
where a library uses them for thread context but in a less structured
way. Something like "set current rounding mode" is I think a good
example. Suppose a math library has a setRoundingMode method which
sets the rounding mod for all subsequent math operations in the
library and suppose it keeps that information in a thread local.
Suppose one task is executed by a pool thread and sets the rounding
mode to something 'special', does its work and completes. Now a second
task is run by that same thread and it uses the library too and
"inherits" the special rounding mode. That's not good. In this case
the "thread-local" really needed to be "task-local" but tasks are not
a language or library concept so we can't do that. Now obviously there
are a few things together that make this go wrong and which could be
fixed:
 - the first thread could restore the rounding mode to normal when it
is finished. This basically takes us back to the setup/cleanup
protocol.
 - the second thread could explicitly set the rounding mode to normal
when it starts
Both of these would fix things such that you don't need to clear the
threadlocal. And both are reasonable things to do when a task does not
assume that it always executes in its own brand new pristine thread.

Someone suggested clearing all threadlocals and then putting back the
ones that matter. Turning that around: if you know about the thread
locals you will use then you can simply clear the ones that do matter.
The argument for removeAllThreadLocals is to deal with the situation
where a task does not know what threadlocals it will use as they are
internal library details.

Bottom line - for me: the situations in which it is necessary to clear
a thread local when using a thread pool, is a very small and narrow
set of use cases for thread locals. The majority of threadlocal usages
would not be affected one way or the other, except perhaps for some
performance loss. In a very small number of cases clearing the
thread-local would cause a problem - but I'm not convinced of the
merits of the usage in such situations (eg the logging example).

But given that people have been using thread pools and thread-locals
for some time now and they have not had removeAllThreadlocals, there
has been no demonstrated need for it - mainly I think because most
reasonable use cases fall in the don't care category. Consequently,
there is no justification for adding it at this time.

David Holmes