| Document Number: | N3070=10-0060 | 
| Date: | 2010-03-11 | 
| Author: | Anthony
      Williams Just Software Solutions Ltd  | 
thread_local VariablesThis paper replaces my earlier paper N3038. It provides a simpler
  and more focused solution to the problem of the interactions
  of thread_local variables and detached threads.
As Hans Boehm and Lawrence Crowl pointed out in N2880, detached
  threads pose a problem for objects with thread storage duration. If
  we use a mechanism other than thread::join to wait for
  a thread to complete its work — such as waiting for a
  future to be ready — then N2880 correctly
  highlights that under the current working paper the destructors
  of thread_local variables will still be running after
  the waiting thread has resumed. This paper proposes a mechanism to
  make such synchronization safe by ensuring that the objects with
  thread storage duration are destroyed prior to the future being made
  ready. e.g.
int find_the_answer(); // uses thread_local objects
void thread_func(std::promise<int> * p)
{
    p->set_value_at_thread_exit(find_the_answer());
}
int main()
{
    std::promise<int> p;
    std::thread t(thread_func,&p);
    t.detach(); // we're going to wait on the future
    std::cout<<p.get_future().get()<<std::endl;
}
When the call to get() returns, we know that not only
  is the future value ready, but the thread_local
  variables on the other thread have also been destroyed.
Such mechanisms are provided
  for std::condition_variable, std::promise
  and std::packaged_task. e.g.
void task_executor(std::packaged_task<void(int)> task,int param)
{
    task.make_ready_at_thread_exit(param); // execute stored task
} // destroy thread_locals and wake threads waiting on futures from task
Other threads can wait on a future obtained from the
  task without having to worry about races due to the execution of
  destructors of the thread_local objects from the task's
  thread.
std::condition_variable cv;
std::mutex m;
complex_type the_data;
bool data_ready;
void thread_func()
{
    std::unique_lock<std::mutex> lk(m);
    the_data=find_the_answer();
    data_ready=true;
    std::notify_all_at_thread_exit(cv,std::move(lk));
} // destroy thread_locals, notify cv, unlock mutex
void waiting_thread()
{
    std::unique_lock<std::mutex> lk(m);
    while(!data_ready)
    {
        cv.wait(lk);
    }
    process(the_data);
}
The waiting thread is guaranteed that the thread_local
  objects used by thread_func() have been destroyed by
  the time process(the_data) is called. If the lock
  on m is released and reacquired after
  setting data_ready and before
  calling std::notify_all_at_thread_exit() then this
  does NOT hold, since the thread may return from the
  wait due to a spurious wakeup.
std::condition_variableAdd the following non-member function following the class definition
of condition_variable in 30.5.1:
    void notify_all_at_thread_exit(std::condition_variable& cond,std::unique_lock<std::mutex> lk);
Insert a new paragraph following 30.5.1p37:
    void notify_all_at_thread_exit(std::condition_variable& cond,std::unique_lock<std::mutex> lk);
lk is locked by the calling thread and either 
    cond orlk.mutex() returns the same value for each of the
        lock arguments supplied by all concurrently waiting
        (via wait, wait_for
        or wait_until) threads.Transfer ownership of the lock associated with lk
      into internal storage and schedule cond to be notified
      when the current thread exits, after all objects of thread storage
      duration associated with the current thread have been
      destroyed. This notification shall be as-if
lk.unlock(); cond.notify_all();
[Note: The supplied lock will be held until the thread exits,
      and care must be taken to ensure that this does not cause
      deadlock due to lock ordering issues. After calling
      notify_all_at_thread_exit it is recommended that
      the thread should be exited as soon as possible, and that no
      blocking or time-consuming tasks are run on that thread. —
      End Note]
[Note: It is the user's responsibility to ensure that waiting
      threads do not erroneously assume that the thread has finished if
      they experience spurious wake-ups. This typically requires that the
      condition being waited for is satisfied whilst holding the lock
      on lk, and that this lock is not released and
      reacquired prior to calling notify_all_at_thread_exit.
      — End Note]
std::promise and std::packaged_taskAdd the following to the class definition
  of std::promise in section 30.6.5
  [futures.promise]:
void set_value_at_thread_exit(const R& r); void set_value_at_thread_exit(see below); void set_exception_at_thread_exit(exception_ptr p);
Modify the error conditions for set_value in 30.6.5 [futures.promise] p19:
promise_already_satisfied if the
      associated asynchronous state no_state if *this has no
      associated asynchronous state.Modify the error conditions for set_exception in 30.6.5 [futures.promise] p23:
promise_already_satisfied if the
      associated asynchronous state no_state if *this has no
      associated asynchronous state.Add the following to the end of section 30.6.5 [futures.promise]:
void promise::set_value_at_thread_exit(const R& r); void promise::set_value_at_thread_exit(R&& r); void promise<R&>::set_value_at_thread_exit(R& r); void promise<void>::set_value_at_thread_exit();
future_error if an error condition occurs.promise_already_satisfied if its associated
        asynchronous state already has a stored value or
        exception.no_state if *this has no
        associated asynchronous state.void set_exception_at_thread_exit(exception_ptr p);
future_error if an error condition occurs.promise_already_satisfied if its associated
        asynchronous state already has a stored value or
        exception.no_state if *this has no
        associated asynchronous state.Added the following member function to the class definition
  for std::packaged_task in 30.6.10 [futures.task]:
void make_ready_at_thread_exit(ArgTypes...);
Modify the error conditions for operator() in 30.6.10
[futures.task] p25:
no_state if *this has no
      associated asynchronous state.promise_already_satisfied if the
      associated asynchronous state Add the following to 30.6.10 [futures.task] following paragraph 26:
void make_ready_at_thread_exit(ArgTypes... args);
*this and t1, t2, ...,
      tN are the values in args.... If the task
      returns normally, the return value is stored in the associated
      asynchronous state, otherwise the exception thrown by the task
      is stored. In either case, this shall be done without making the
      state ready immediately. Schedules the associated
      asynchronous state to be made ready when the current
      thread exits, after all objects of thread storage duration
      associated with the current thread have been destroyed.future_error if an error condition occurs.promise_already_satisfied if its associated
        asynchronous state already has a stored value or
        exception.no_state if *this has no
        associated asynchronous state.