libjmmcg  release_579_6_g8cffd
A C++ library containing an eclectic mix of useful, advanced components.
thread_os_traits.hpp
Go to the documentation of this file.
1 #ifndef LIBJMMCG_CORE_THREAD_OS_TRAITS_HPP
2 #define LIBJMMCG_CORE_THREAD_OS_TRAITS_HPP
3 
4 /******************************************************************************
5 ** Copyright © 2004 by J.M.McGuiness, coder@hussar.me.uk
6 **
7 ** This library is free software; you can redistribute it and/or
8 ** modify it under the terms of the GNU Lesser General Public
9 ** License as published by the Free Software Foundation; either
10 ** version 2.1 of the License, or (at your option) any later version.
11 **
12 ** This library is distributed in the hope that it will be useful,
13 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
14 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 ** Lesser General Public License for more details.
16 **
17 ** You should have received a copy of the GNU Lesser General Public
18 ** License along with this library; if not, write to the Free Software
19 ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 */
21 
23 
24 namespace jmmcg { namespace LIBJMMCG_VER_NAMESPACE {
25 
26  namespace ppd {
27 
28  /// This class is used to encapsulate the OS-specific threading traits, mutexes, etc for the "thread_pool<...>" and other classes.
29  template<generic_traits::api_type API, typename Mdl>
31  typedef api_threading_traits<API, Mdl> thread_traits;
33  typedef typename lock_traits::exception_type exception_type; ///< A base exception-type for use in classes that use this trait.
34 
35  /// Used to assist passing exceptions between threads.
36  /**
37  Note that this class is not thread-safe - it presumes that access to it, although from different threads, will always be sequential. (i.e. not simultaneous.)
38  It also propagates any contained exception only once - to the calling thread. (Thus if it were truly multi-thread-safe it should propagate the exception to all calling threads.)
39  But then the whole paradigm of the execution context is that only one thread at a time should wait on the results from it.
40 
41  \todo Make use of std::exception_ptr or similar to pass any thrown exception.
42  */
44  public:
45  /**
46  We only want one thread to throw the exception, despite the fact that many may be connected to it, see specification of throw_if_set().
47 
48  Note that this implementation can use raw pointers and operate correctly on SMP architectures that support the MESI or MOESI architectures (and may work correctly with other implementations), without needing to use more complex operations. But we use allow the potential for the more complex operations here to support those more hairy architectures.
49  */
50  typedef std::exception_ptr exception_t;
51 
52  constexpr thread_exception() noexcept(true) FORCE_INLINE
53  : thread_except() {
54  }
55  /**
56  Don't throw any registered exception here, as it could lead to huge wobbling great nasty memory leaks.
57  Just hope that someone called the throw_if_set() before hand.
58  (e.g. in get_results() or destructor in the execution context or in the destructor of the thread wrapper.)
59 
60  \see throw_if_set()
61  \see execution_context_stack_type
62  */
63  ~thread_exception() noexcept(true) FORCE_INLINE {
64  thread_except=exception_t();
65  }
66 
67  template<class Ex> void __fastcall FORCE_INLINE
68  set(Ex const &e) const noexcept(true) {
69  thread_except=std::make_exception_ptr(e);
70  assert(thread_except);
71  }
72  void __fastcall set(std::exception_ptr e) const noexcept(true) FORCE_INLINE {
73  thread_except=e;
74  assert(thread_except);
75  }
76 
77  /// Throw any contained exception, but only once.
78  /**
79  Note that this function is not atomic - but then it is an error to allow multiple threads to access this class simultaneously.
80  */
81  void __fastcall throw_if_set() const noexcept(false) FORCE_INLINE {
82  if (thread_except) {
83  const exception_t except_to_throw(thread_except);
84  thread_except=exception_t();
85  // See - the exception is thrown only once. Otherwise it could also get thrown here & in the destructor of the thread-class.
86  std::rethrow_exception(except_to_throw);
87  }
88  }
89 
90  /**
91  \todo Implement using the advice given in "Standard C++ IOStreams and Locales" by A.Langer & K.Kreft, page 170.
92  */
93  friend tostream & __fastcall FORCE_INLINE
94  operator<<(tostream &os, thread_exception const &te) noexcept(false) {
95  if (te.thread_except!=nullptr) {
96  os<<_T("Exception has been thrown in thread.");
97  } else {
98  os<<_T("No exception thrown.");
99  }
100  return os;
101  }
102 
103  private:
104  mutable exception_t thread_except;
105  };
106  };
107 
108 } } }
109 
110 #endif