library of assembled shared sources |
http://lass.cocamware.com |
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 1.5.7.1 |