zach
zach

Reputation: 23

why "boost.thread" call "intrusive_ptr_add_ref" manually?

In boost.thread's start function, the source code is something like that:

bool thread::start_thread_noexcept()
{
    uintptr_t const new_thread = _beginthreadex(
            0, 
            0, 
            &thread_start_function,     
            thread_info.get(),          
            CREATE_SUSPENDED,           
            &thread_info->id);          

    if (!new_thread)
    {
        return false;
    }

    // why call this line?
    intrusive_ptr_add_ref(thread_info.get());

    thread_info->thread_handle = (detail::win32::handle)(new_thread);
    ResumeThread(thread_info->thread_handle);
    return true;
}

thread_info is a intrusive smart pointer which points to the thread information data, before calling the intrusive_ptr_add_ref, the count is already 1, I don't know why call the intrusive_ptr_add_ref mannually here. I think Intrusive smart pointer's job should be calling the intrusive_ptr_add_ref and intrusive_ptr_release automatically.

I've tried to step through the source code but didn't find any clue.

Can anyone tell me 1. why call intrusive_ptr_add_ref manually here? 2. In what condition when using the intrusive_ptr, I should call intrusive_ptr_add_ref manually?

Thanks, Sincerely.

Upvotes: 2

Views: 249

Answers (1)

Nicol Bolas
Nicol Bolas

Reputation: 474326

why call intrusive_ptr_add_ref manually here?

To represent the sharing of ownership of the pointer.

_beginthreadex was passed thread_info.get() as a parameter. This parameter will be passed to thread_start_function when the thread starts. And this function expects the pointer to remain valid until that happens.

Now, _beginthreadex is a simple function. It's not a variadic template that can take arbitrary parameters or anything. It takes exactly and only a naked pointer, and passes exactly that to the start function.

It is very possible for the person creating the boost::thread to call thread::detach before thread_start_function ever gets called. And if that happened, then the thread_info intrusive pointer would be destroyed, thus causing the destruction of its contained object.

And that leaves _beginthreadex with a destroyed pointer. That's bad.

What _beginthreadex needs to do is claim ownership of the intrusvie pointer. But since the API doesn't take a boost::intrusive_ptr, how do you do that?

By bumping the reference count. The reference count increase is how _beginthreadex claims ownership of the object.

Upvotes: 1

Related Questions