|
Boost : |
From: Chuck Messenger (chuckm_at_[hidden])
Date: 2003-06-02 14:39:00
William E. Kempf wrote:
> Chuck Messenger said:
>
>>I've been experimenting with the thread lib. I found a bug related in
>>some way to thread_specific_storage (tss). In particular, I #ifdef'd
>>all the tss stuff out, using native pthread calls instead, and
>>everything worked as expected.
>>
>>So, I went back through, trying to determine what could be going on.
>>I'm using tss to store a pointer to a thread-wide structure.
>>
>> thread_specific_ptr<mythread*> current_thread;
>>
>> mythread *mythread_get() {
>> return *(current_thread.get());
>> }
>>
>> static int init() {
>> // Need to initialize thread local storage for main thread
>>
>> // XXX I'd like to put something here to ensure that
>> // current_thread has been constructed. But what?
>>
>> current_thread.reset(new mythread *);
>> *(current_thread.get()) = new mythread;
>>
>> return 0;
>> }
>>
>> static int val = init();
>
> I don't follow what you're code is supposed to be doing.
Background: I have a structure of information, 'mythread', of which I
need one per thread. That is, I've grouped all my tss variables into a
single structure. I need to "bootstrap" the main thread. Hence the
static variable initialization -- my thought (perhaps incorrect) being
that 'val' will be initialized before main() begins, thus bootstrapping
the main thread. I believe that's right -- that all static variables in
all translation units are initialized before main()...?
(The point is that I don't have control of main() -- otherwise, I could
initialize current_thread in main(). This code is part of a library.)
> 'val' always is
> assigned 0. Is it's only purpose to cause the call to init()?
Yes.
> Why would
> you want to do that in this manner? It seems to me the solution you need
> is as simple as:
>
> mythread *mythread_get() {
> mythread* t = *(current_thread.get());
> if (t == 0)
> current_thread.reset(new mythread *);
> return t;
> }
I was, perhaps misguidedly, trying to avoid the need to call a function
-- since I access the mythread structure alot. Ideally, I want as much
speed as the underlying OS-level implementation will allow.
> However, why thread_specific_ptr<mythread*>? My not just
> thread_specific_ptr<mythread>? This code doesn't look valid to me, but
> with out context I'm guessing.
Because I don't want the 'mythread' structure to get deleted when the
thread dies. My understanding of tss is that part of the semantics is
that, if you do
some_tss_value.reset(whatever);
then when the thread ends, the thread library does 'delete whatever'.
Therefore, I'm forced to have tss store a pointer to mystruct*, rather
than mystruct* itself.
>>The problem is that I can't be sure, during init(), that current_thread
>>has been constructed. I believe that's at the root of the bug I'm
>>tracking.
>>
>>By contrast, in my pthread-specific code, I simply put the
>>pthread_key_create() call at the start of init(), thus ensuring proper
>>initialization order. But there's no analogous call I can make for a
>>thread_specific_ptr -- that call is done during construction time.
>
>
> pthread_key_create() only creates the key, it does not create any of the
> thread specific storage for which there'd be an initialization order
> issue. So, I don't understand what you're doing or what the problem is.
The problem is that it is necessary for pthread_key_create() to be
called before I can set a value for it. Can I be sure that
thread_specific_ptr<mythread*> has been initialized before I try using
it during init()? I'm not that clear on C++ initialization order
semantics for statics. If I do:
extern int i;
extern int j;
int j = i;
int i = j;
then what happens? It isn't obvious to me how the order would be
established. And so, can I assume that the following is guaranteed to work?
static SomeType var1;
static AnotherType var2 = var1.something();
That is, is var1 guaranteed to be constructed before I initialize var2
from it?
The thing is: there is some sort of bug with (Boost Threads) TSS -- the
way I'm using it, that is. My attempts at tracking the bug failed, so I
resorted to replacing TSS with native pthreads, and that worked. The
only difference that I could glean between the TSS and pthreads versions
of my code were in init(). If I spent some more time on it, perhaps I
could definitively nail down this suspicion.
So, as it is, I *suspect* that the problem is that "accessing a static
thread_specific_ptr<> during initialization of another static variable"
isn't guaranteed to work (because C++ doesn't, perhaps, define
initialization order for statics, so the thread_specific_ptr<> object
won't necessarily have been created by the time it is used).
Assuming this is correct, then I'm proposing a new force_construction()
method for thread_specific_ptr<>, to ameliorate this kind of problem.
During thread_specific_ptr<>'s normal construction, it would detect
whether it had been "pre-constructed".
>>Which brings me to another source of slowness: because
>>thread_specific_ptr automatically invokes delete on a thread's tss
>>pointers when the thread goes away, I can't put a pointer to my real
>>object, like this:
>>
>> thread_specific_ptr<mythread> current_thread;
>>
>>because mythread can't be deleted (for arcane reasons I won't get into
>>here).
>
> That depends. As long as you can set the value back to 0 before the
> thread ends, you can still put this into thread_specific_ptr<>. Not a
> universal solution, obviously, I just point it out in case it may help
> with your current use case.
OK -- that's a possibility. Thanks.
- Chuck Messenger
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk