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



_______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost

Reply via email to