Boost logo

Boost :

Subject: Re: [boost] [thread] TSS complexity
From: vicente.botet (vicente.botet_at_[hidden])
Date: 2008-09-22 17:42:19


----- Original Message -----
From: "Anthony Williams" <anthony.ajw_at_[hidden]>
To: <boost_at_[hidden]>
Sent: Monday, September 22, 2008 6:05 PM
Subject: Re: [boost] [thread] TSS cleanup

>> For example:
>>
>> for(int i = very_big_number;i--;i > 0)
>> boost::thread_specific_ptr<int> p(new int);
>>
>> To my knowledge, the pointer returned by new in this case is freed.
>> But does the int* that is created to store the pointer to new int is also
>> freed, or this program will get only bigger and bigger?
>
> As written this code is fine: it will reuse the same slot since p will
> have the same address each time through, and it uses the address as
> the key. It is undefined behaviour if other threads can still try and
> access a given thread_specific_ptr (including having data stored
> associated with it) after it has been destroyed.

Hi,

I didn't know that the key was the address of the variable. As
pthread_getspecific ensures constant complexity, I expected the same for
boost::thread_specific_ptr, but if the key is the address this seams not
possible. So which is the complexity of
boost::thread_specific_ptr<T>::get()? Looking at the code we see that is
O(N). IMHO, the constant complexity is one the major requirements of such a
feature. I supose you had some good raison to not use an index key instead
of the address.

In addition, the release and reset functions inccur on two lookups on the
set of thread specific pointers.

T* release() {
    T* const temp=get();
    detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
    return temp;
}
void reset(T* new_value=0) {
    T* const current_value=get();
    if(current_value!=new_value)
    {
        detail::set_tss_data(this,cleanup,new_value,true);
    }
}

If the set_tss_data returns the old value these two functions could be
encoded with reduced complexity like that.
T* release() {
        return
detail::set_tss_data(this,boost::shared_ptr<detail::tss_cleanup_function>(),0,false);
}
void reset(T* new_value=0) {
        detail::set_tss_data(this,cleanup,new_value,true);
}

Does the thread_local C++0x feature requires constant complexity on getting
and setting the value?
It is a pitie that we can not use the thread_local (or the equivalent) when
the compiler provies to define boost::thread_specific_ptr. Or maybe the
preprocesor can help?

#define BOOST_THREAD_LOCAL(T,name,init_value) \
class BOOST_THREAD_LOCAL##name {
private:
    thread_local static T value init_value;
public:
    T* get() const { return &value; }
} name;

In the mean time, it would be great if you add the nature of the key, the
complexity and the rationale on this design decision on the documentation.

Thanks,

Vicente


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk