$include_dir="/home/hyper-archives/boost-commit/include"; include("$include_dir/msg-header.inc") ?>
Subject: [Boost-commit] svn:boost r81282 - trunk/libs/thread/doc
From: vicente.botet_at_[hidden]
Date: 2012-11-10 05:32:07
Author: viboes
Date: 2012-11-10 05:32:06 EST (Sat, 10 Nov 2012)
New Revision: 81282
URL: http://svn.boost.org/trac/boost/changeset/81282
Log:
Thread: update doc with lockable traits, yuturial, compliance.
Text files modified: 
   trunk/libs/thread/doc/compliance.qbk     |    17 +-                                      
   trunk/libs/thread/doc/future_ref.qbk     |    14 +-                                      
   trunk/libs/thread/doc/futures.qbk        |   184 +++++++++++++++++++++++++++++++++++++++ 
   trunk/libs/thread/doc/mutex_concepts.qbk |    65 +++++++++++++                           
   4 files changed, 261 insertions(+), 19 deletions(-)
Modified: trunk/libs/thread/doc/compliance.qbk
==============================================================================
--- trunk/libs/thread/doc/compliance.qbk	(original)
+++ trunk/libs/thread/doc/compliance.qbk	2012-11-10 05:32:06 EST (Sat, 10 Nov 2012)
@@ -25,10 +25,10 @@
     [[30.2.5.3]        [Lockable requirements]  [yes] [-] [-]]
     [[30.2.5.4]        [TimedLockable requirements]  [Yes] [-] [-]]
     [[30.2.6]        [decay_copy]  [-] [-] [-]]
-    [[30.3]        [Threads]  [Partial] [-] [-]]
-    [[30.3.1]        [Class thread]  [Partial] [move,variadic,terminate] [#6270]]
+    [[30.3]        [Threads]  [Yes] [-] [-]]
+    [[30.3.1]        [Class thread]  [Yes] [-] [-]]
     [[30.3.1.1]        [Class thread::id]  [Yes] [-] [-]]
-    [[30.3.1.2]        [thread constructors]  [Partial] [move,variadic] [#6270]]
+    [[30.3.1.2]        [thread constructors]  [Partial] [-] [-]]
     [[30.3.1.3]        [thread destructor]  [Yes] [-] [-]]
     [[30.3.1.4]        [thread assignment]  [Yes] [-] [-]]
     [[30.3.1.5]        [thread members]  [Yes] [-] [-]]
@@ -56,20 +56,19 @@
     [[30.4.4]        [Call once]  [Partial] [call_once] [#7285]]
     [[30.4.4.1]        [Struct once_flag] [Yes] [-] [-]]
     [[30.4.4.2]        [Function call_once] [Partial] [interface] [#7285]]
-    [[30.5]        [Condition variables]  [Partial] [notify_all_at_thread_exit] [#7283]]
-    [[30.5 6-10]        [Function notify_all_at_thread_exit]  [No] [-] [#7283]]
+    [[30.5]        [Condition variables]  [Yes] [-] [-]]
     [[30.5.1]        [Class condition_variable]  [Yes] [-] [-]]
     [[30.5.2]        [Class condition_variable_any]  [Yes] [-] [-]]
-    [[30.6]        [Futures]  [Partial] [async,at_thread_exit] [#4710,#7280]]
+    [[30.6]        [Futures]  [Partial] [noexcept] [#7279]]
     [[30.6.1]        [Overview]  [Partial] [-] [-]]
     [[30.6.2]        [Error handling]  [Yes] [-] [-]]
     [[30.6.3]        [Class future_error]  [Partial] [noexcept] [#7279]]
     [[30.6.4]        [Shared state]  [-] [-] [-]]
-    [[30.6.5]        [Class template promise]  [Partial] [at_thread_exit] [#7280]]
+    [[30.6.5]        [Class template promise]  [Yes] [-] [-]]
     [[30.6.6]        [Class template future]  [Yes] [-] [-]]
     [[30.6.7]        [Class template shared_future]  [Yes] [-] [-]]
-    [[30.6.8]        [Function template async]  [Partial] [deferred not implemented and only a copyable functor is allowed yet] [#4710]]
-    [[30.6.9]        [Class template packaged_task]  [Partial] [args,make_ready_at_thread_exit] [#7281,#7282]]
+    [[30.6.8]        [Function template async]  [Yes] [-] [-]]
+    [[30.6.9]        [Class template packaged_task]  [Yes] [-] [-]]
 ]
 
 [/
Modified: trunk/libs/thread/doc/future_ref.qbk
==============================================================================
--- trunk/libs/thread/doc/future_ref.qbk	(original)
+++ trunk/libs/thread/doc/future_ref.qbk	2012-11-10 05:32:06 EST (Sat, 10 Nov 2012)
@@ -117,7 +117,7 @@
 [endsect]
 
 
-[section:future_errc Enumeration `future_errc `]
+[section:future_errc Enumeration `future_errc`]
 
   enum class future_errc
   {
@@ -131,7 +131,7 @@
  The enum values of future_errc are distinct and not zero. 
  
 [endsect]
-[section:launch Enumeration `launch `]
+[section:launch Enumeration `launch`]
 
     enum class launch
     {
@@ -277,7 +277,7 @@
       R&& get();
 
       // functions to check state
-      bool valid() const;
+      bool valid() const noexcept;
       bool is_ready() const; // EXTENSION
       bool has_exception() const; // EXTENSION
       bool has_value() const; // EXTENSION
@@ -424,7 +424,7 @@
 
 [section:wait Member function `wait()`]
 
-    void wait();
+    void wait() const;
 
 [variablelist
 
@@ -605,7 +605,7 @@
 
 [section:valid Member function `valid()`]
 
-    bool valid() const;
+    bool valid() const noexcept;
 
 [variablelist
 
@@ -827,7 +827,7 @@
 
 [section:wait Member function `wait()`]
 
-    void wait();
+    void wait() const;
 
 [variablelist
 
@@ -989,7 +989,7 @@
 
 [section:valid Member function `valid()`]
 
-    bool valid() const;
+    bool valid() const noexcept;
 
 [variablelist
 
Modified: trunk/libs/thread/doc/futures.qbk
==============================================================================
--- trunk/libs/thread/doc/futures.qbk	(original)
+++ trunk/libs/thread/doc/futures.qbk	2012-11-10 05:32:06 EST (Sat, 10 Nov 2012)
@@ -93,10 +93,13 @@
 appropriate for the type.
 
 On the other hand, many instances of __shared_future__ may reference the same result. Instances can be freely copied and assigned,
-and __shared_future_get__ returns a `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
+and __shared_future_get__ returns a non `const` reference so that multiple calls to __shared_future_get__ are safe. You can move an
 instance of __unique_future__ into an instance of __shared_future__, thus transferring ownership of the associated asynchronous
 result, but not vice-versa.
 
+`boost::async` is a simple way of running asynchronous tasks. A call to `boost::async` returns a __unique_future__ that will contain the result of the task.
+
+
 You can wait for futures either individually or with one of the __wait_for_any__ and __wait_for_all__ functions.
 
 [endsect]
@@ -184,7 +187,186 @@
 
 [endsect]
 
+[section:at_thread_exit Handling Detached Threads and Thread Specific Variables]
+
+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 the destructors of thread specific variables will still be running after the waiting thread has resumed. 
+This section explain how the standard mechanism can be used 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 specific objects
+  void thread_func(boost::promise<int>&& p)
+  {
+      p.set_value_at_thread_exit(find_the_answer());
+  }
+  
+  int main()
+  {
+      boost::promise<int> p;
+      boost::thread t(thread_func,boost::move(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 specific variables 
+on the other thread have also been destroyed.
+
+Such mechanisms are provided for `boost::condition_variable`, `boost::promise` and `boost::packaged_task`. e.g.
+
+  void task_executor(boost::packaged_task<void(int)> task,int param)
+  {
+      task.make_ready_at_thread_exit(param); // execute stored task
+  } // destroy thread specific 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 specific objects from the task's thread.
+
+  boost::condition_variable cv;
+  boost::mutex m;
+  complex_type the_data;
+  bool data_ready;
+  
+  void thread_func()
+  {
+      boost::unique_lock<std::mutex> lk(m);
+      the_data=find_the_answer();
+      data_ready=true;
+      boost::notify_all_at_thread_exit(cv,boost::move(lk));
+  } // destroy thread specific objects, notify cv, unlock mutex
+  
+  void waiting_thread()
+  {
+      boost::unique_lock<std::mutex> lk(m);
+      while(!data_ready)
+      {
+          cv.wait(lk);
+      }
+      process(the_data);
+  }
+
+The waiting thread is guaranteed that the thread specific objects used by `thread_func()` have been destroyed by the time 
+`process(the_data)` is called. If the lock on `m` is released and re-acquired after setting `data_ready` and before calling 
+`boost::notify_all_at_thread_exit()` then this does NOT hold, since the thread may return from the wait due to a 
+spurious wake-up.
+
+[endsect]
+
 [section:async Executing asynchronously]
+
+`boost::async` is a simple way of running asynchronous tasks to make use of the available hardware concurrency. 
+A call to `boost::async` returns a `boost::future` that will contain the result of the task. Depending on 
+the launch policy, the task is either run asynchronously on its own thread or synchronously on whichever thread
+calls the `wait()` or `get()` member functions on that `future`.
+
+A launch policy of either boost::launch::async, which asks the runtime to create an asynchronous thread,
+or boost::launch::deferred, which indicates you simply want to defer the function call until a later time (lazy evaluation). 
+This argument is optional - if you omit it your function will use the default policy.
+
+For example, consider computing the sum of a very large array. The first task is to not compute asynchronously when 
+the overhead would be significant. The second task is to split the work into two pieces, one executed by the host 
+thread and one executed asynchronously.
+
+
+    int parallel_sum(int* data, int size)
+    {
+      int sum = 0;
+      if ( size < 1000 )
+        for ( int i = 0; i < size; ++i )
+          sum += data[i];
+      else {
+        auto handle = boost::async(parallel_sum, data+size/2, size-size/2);
+        sum += parallel_sum(data, size/2);
+        sum += handle.get();
+      }
+      return sum;
+    }
+
+
+
+[endsect]
+
+[section:shared Shared Futures]
+
+`shared_future` is designed to be shared between threads, 
+that is to allow multiple concurrent get operations.
+
+[heading Multiple get]
+
+The second `get()` call in the following example future  
+
+  void bad_second_use( type arg ) {
+      
+    auto ftr = async( [=]{ return work( arg ); } );
+      if ( cond1 ) 
+      {
+          use1( ftr.get() );
+      } else 
+      {
+          use2( ftr.get() );
+      }
+      use3( ftr.get() ); // second use is undefined
+  }
+    
+Using a `shared_mutex` solves the issue
+
+  void good_second_use( type arg ) {
+      
+     shared_future<type> ftr = async( [=]{ return work( arg ); } );
+      if ( cond1 ) 
+      {
+          use1( ftr.get() );
+      } else 
+      {
+          use2(  ftr.get() );
+      }
+      use3( ftr.get() ); // second use is defined
+  }
+
+[heading share()]
+  
+Namming the return type when declaring the `shared_future` is needed; auto is not available within template argument lists. 
+Here `share()` could be used to simplify the code
+
+  void better_second_use( type arg ) {
+      
+     auto ftr = async( [=]{ return work( arg ); } ).share();
+      if ( cond1 ) 
+      {
+          use1( ftr.get() );
+      } else 
+      {
+          use2(  ftr.get() );
+      }
+      use3( ftr.get() ); // second use is defined
+  }
+ 
+[heading Writting on get()]
+
+The user can either read or write the future avariable. 
+
+  void write_to_get( type arg ) {
+      
+     auto ftr = async( [=]{ return work( arg ); } ).share();
+      if ( cond1 ) 
+      {
+          use1( ftr.get() );
+      } else 
+      {
+        if ( cond2 ) 
+          use2(  ftr.get() );
+        else
+          ftr.get() = something(); // assign to non-const reference.  
+      }
+      use3( ftr.get() ); // second use is defined
+  }
+     
+This works because the `shared_future<>::get()` function returns a non-const reference to the appropriate storage.
+Of course the access to this storage must be ensured by the user. The library doesn't ensure the access to the internal storage is thread safe.
+
+There has been some work by the C++ standard committe on an `atomic_future` that behaves as an `atomic` variable, that is is thread_safe, 
+and a `shared_future` that can be shared between several threads, but there were not enough consensus and time to get it ready for C++11.       
+
 [endsect]
 
 [section:make_future Making immediate futures easier]
Modified: trunk/libs/thread/doc/mutex_concepts.qbk
==============================================================================
--- trunk/libs/thread/doc/mutex_concepts.qbk	(original)
+++ trunk/libs/thread/doc/mutex_concepts.qbk	2012-11-10 05:32:06 EST (Sat, 10 Nov 2012)
@@ -80,18 +80,33 @@
 [endsect]
 
 
+[section:is_basic_lockable `is_basic_lockable` trait]
+
+  // #include <boost/thread/lockable_traits.hpp> 
+
+  namespace boost 
+  {
+    namespace sync 
+    {
+      template<typename L>
+      class is_basic_lockable;
+    }
+  }
+
+Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of BasicLockable you could build. 
+
 [endsect]
+[endsect]
+
 [section:lockable `Lockable` Concept]
 
   // #include <boost/thread/lockable_concepts.hpp> 
-
   namespace boost 
   {
     template<typename L>
     class Lockable;
   }
 
-
 A type `L` meets the __Lockable requirements if it meets the __BasicLockable requirements and the following expressions are well-formed and have the specified semantics (`m` denotes a value of type `L`):
 
 * `m.__try_lock()`
@@ -115,7 +130,53 @@
 ]
 [endsect]
 
+[section:is_lockable `is_lockable` trait]
+
+  // #include <boost/thread/lockable_traits.hpp> 
+  namespace boost 
+  {
+    namespace sync 
+    {
+      template<typename L>
+      class is_lockable;
+    }
+  }
+
+Some of the algorithms on mutexes use this trait via SFINAE. If BOOST_THREAD_NO_AUTO_DETECT_MUTEX_TYPES is defined you will need to specialize this traits for the models of Lockable you could build. 
+
 [endsect]
+[endsect]
+
+[section:recursive Recursive Lockable Concept]
+
+The user could require that the mutex passed to an algorithm is a recursive one. Whether a lockable is recursive or not can not be checked using template meta-programming. This is the motivation for the following trait.
+
+
+[section:is_recursive_mutex_sur_parolle `is_recursive_mutex_sur_parolle` trait]
+
+  // #include <boost/thread/lockable_traits.hpp> 
+
+  namespace boost 
+  {
+    namespace sync 
+    {
+      template<typename L>
+      class is_recursive_mutex_sur_parolle: false_type;
+      template<>
+      class is_recursive_mutex_sur_parolle<recursive_mutex>: true_type;
+      template<>
+      class is_recursive_mutex_sur_parolle<timed_recursive_mutex>: true_type;
+    }
+  }
+
+The trait `is_recursive_mutex_sur_parolle` is `false_type` by default and is specialized for the provide `recursive_mutex` and `timed_recursive_mutex`. 
+
+It should be specialized by the user providing other model of recursive lockable.
+
+[endsect]
+
+[endsect]
+
 
 [section:timed_lockable `TimedLockable` Concept]