library of assembled shared sources

http://lass.cocamware.com

future.h

Go to the documentation of this file.
00001 /** @file
00002  *  @author Bram de Greve (bramz@users.sourceforge.net)
00003  *  @author Tom De Muer (tomdemuer@users.sourceforge.net)
00004  *
00005  *  *** BEGIN LICENSE INFORMATION ***
00006  *  
00007  *  The contents of this file are subject to the Common Public Attribution License 
00008  *  Version 1.0 (the "License"); you may not use this file except in compliance with 
00009  *  the License. You may obtain a copy of the License at 
00010  *  http://lass.sourceforge.net/cpal-license. The License is based on the 
00011  *  Mozilla Public License Version 1.1 but Sections 14 and 15 have been added to cover 
00012  *  use of software over a computer network and provide for limited attribution for 
00013  *  the Original Developer. In addition, Exhibit A has been modified to be consistent 
00014  *  with Exhibit B.
00015  *  
00016  *  Software distributed under the License is distributed on an "AS IS" basis, WITHOUT 
00017  *  WARRANTY OF ANY KIND, either express or implied. See the License for the specific 
00018  *  language governing rights and limitations under the License.
00019  *  
00020  *  The Original Code is LASS - Library of Assembled Shared Sources.
00021  *  
00022  *  The Initial Developer of the Original Code is Bram de Greve and Tom De Muer.
00023  *  The Original Developer is the Initial Developer.
00024  *  
00025  *  All portions of the code written by the Initial Developer are:
00026  *  Copyright (C) 2004-2007 the Initial Developer.
00027  *  All Rights Reserved.
00028  *  
00029  *  Contributor(s):
00030  *
00031  *  Alternatively, the contents of this file may be used under the terms of the 
00032  *  GNU General Public License Version 2 or later (the GPL), in which case the 
00033  *  provisions of GPL are applicable instead of those above.  If you wish to allow use
00034  *  of your version of this file only under the terms of the GPL and not to allow 
00035  *  others to use your version of this file under the CPAL, indicate your decision by 
00036  *  deleting the provisions above and replace them with the notice and other 
00037  *  provisions required by the GPL License. If you do not delete the provisions above,
00038  *  a recipient may use your version of this file under either the CPAL or the GPL.
00039  *  
00040  *  *** END LICENSE INFORMATION ***
00041  */
00042 
00043 /** Transporting Values and Exceptions between Threads
00044  *  @class lass::util::experimental::Future
00045  *
00046  *  See:
00047  *  @arg Peter Dimov: "Transporting Values and Exceptions between Threads", 
00048  *      http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2096.html
00049  *  @arg Matti Rintala: "Handling Multiple Concurrent Exceptions in C++ Using Futures", 
00050  *      teoksessa Advanced Topics in Exception Handling Techniques, 
00051  *      toim. C. Dony, J. L. Knudsen, A. Romanovsky, A. Tripathi. 
00052  *      LNCS 4419, 301 s, ISBN 3-540-37443-4, DOI 10.1007/11818502_4, Springer-Verlag 2006
00053  *      http://www.cs.tut.fi/cgi-bin/run/bitti/download/lncs-eh-draft.pdf
00054  *  @arg Matti Rintala: "Exceptions in remote procedure calls using C++ template metaprogramming", 
00055  *      Software—Practice and Experience, 2007, 37:231-246, 16 s, DOI: 10.1002/spe.754
00056  *      http://www.cs.tut.fi/cgi-bin/run/bitti/download/spe-mmr-preprint.pdf
00057  */  
00058  
00059 #ifndef LASS_GUARDIAN_OF_INCLUSION_UTIL_FUTURE_H
00060 #define LASS_GUARDIAN_OF_INCLUSION_UTIL_FUTURE_H
00061 
00062 #include "util_common.h"
00063 #include "shared_ptr.h"
00064 
00065 namespace lass
00066 {
00067 namespace util
00068 {
00069 namespace experimental
00070 {
00071 
00072 /** @ingroup Thread
00073  *  @relates Future
00074  */
00075 class FutureBindError: public util::Exception
00076 {
00077 public:
00078     FutureBindError(const std::string& msg, const std::string& loc): util::Exception(msg, loc) {}
00079 private:
00080     LASS_UTIL_EXCEPTION_PRIVATE_IMPL(FutureBindError)
00081 };
00082 
00083 
00084 
00085 template <typename T>
00086 class Future
00087 {
00088 public:
00089 
00090     Future(): pimpl_(new Impl) {}
00091 
00092     const bool isBound() const 
00093     {
00094         TLocker lock(pimpl_->mutex_);
00095         return pimpl_->isBound_ || pimpl_->isBadAlloc_ || pimpl_->error_.get(); 
00096     }
00097     const bool operator!() const { return !isBound(); }
00098     operator num::SafeBool() const { return isBound() ? num::safeFalse : num::safeTrue; }
00099 
00100     void wait() 
00101     {
00102         while (!isBound())
00103         {
00104             pimpl_->condition_.wait();
00105         }
00106     }
00107     const WaitResult wait(unsigned long milliSeconds)
00108     {
00109         return pimpl_->condition_.wait() == waitSuccess && isBound() ? waitSuccess : waitTimeout;
00110     }
00111     
00112     const T& operator()() const
00113     {
00114         wait();
00115         TLocker lock(pimpl_->mutex_);
00116         if (pimpl_->isBadAlloc_)
00117         {
00118             throw std::bad_alloc("::lass::Future::bindError: failed to clone exception");
00119         }
00120         if (pimpl_->error_.get())
00121         {
00122             pimpl_->error_->throwSelf();
00123         }
00124         return *reinterpret_cast<T*>(pimpl_->value_);
00125     }
00126 
00127     void bind(const T& value)
00128     {
00129         TLocker lock(pimpl_->mutex_);
00130         if (pimpl_->isBound())
00131         {
00132             LASS_THROW_EX(FutureBindError, "Future is already bound");
00133         }
00134         new (reinterpret_cast<T*>(pimpl_->value_)) T(value);
00135         pimpl_->isBound_ = true;
00136         pimpl_->condition_.broadcast();
00137     }
00138     void unbind()
00139     {
00140         TLocker lock(pimpl_->mutex_);
00141         pimpl_->unbind();
00142     }
00143 
00144     void error(const experimental::RemoteExceptionBase& error)
00145     {
00146         TLocker lock(pimpl_->mutex_);
00147         try
00148         {
00149             pimpl_->error_ = error.clone();
00150         }
00151         catch (std::bad_alloc)
00152         {
00153             pimpl_->isBadAlloc_ = true;
00154         }
00155         pimpl_->condition_.broadcast();
00156     }
00157     template <typename ExceptionType>
00158     void error(const ExceptionType& error)
00159     {
00160         TLocker lock(pimpl_->mutex_);
00161         try
00162         {
00163             pimpl_->error_ = new experimental::RemoteExceptionWrapper<ExceptionType>(error);
00164         }
00165         catch (std::bad_alloc)
00166         {
00167             pimpl_->isBadAlloc_ = true;
00168         }
00169         pimpl_->condition_.broadcast();
00170     }
00171 
00172 private:
00173 
00174     typedef util::Semaphore TMutex;
00175     typedef util::Locker<TMutex> TLocker;
00176 
00177     struct Impl
00178     {
00179         char value_[sizeof(T)];
00180         std::auto_ptr<experimental::RemoteExceptionBase> error_;
00181         Condition condition_;
00182         TMutex mutex_;
00183         size_t referenceCount_;
00184         volatile bool isBound_;
00185         volatile bool isBadAlloc_;
00186 
00187         Impl(): isBound_(false) {}
00188         ~Impl() 
00189         {
00190             unbind();
00191         }
00192         void unbind()
00193         {
00194             if (isBound_)
00195             {
00196                 reinterpret_cast<T*>(value_)->~T();
00197                 isBound_ = false;
00198             }
00199         }
00200     };
00201 
00202     typedef util::IntrusiveCounter<Impl, size_t, &Impl::referenceCount_> TCounterPolicy;
00203     typedef util::SharedPtr<Impl, util::ObjectStorage, TCounterPolicy> TImplPtr;
00204 
00205     TImplPtr pimpl_;
00206 };
00207 
00208 }
00209 }
00210 }
00211 
00212 #endif

Generated on Mon Nov 10 14:20:04 2008 for Library of Assembled Shared Sources by doxygen 1.5.7.1
SourceForge.net Logo