Qpid Proton C++  0.17.0
thread_safe.hpp
1 #ifndef PROTON_THREAD_SAFE_HPP
2 #define PROTON_THREAD_SAFE_HPP
3 
4 /*
5  *
6  * Licensed to the Apache Software Foundation (ASF) under one
7  * or more contributor license agreements. See the NOTICE file
8  * distributed with this work for additional information
9  * regarding copyright ownership. The ASF licenses this file
10  * to you under the Apache License, Version 2.0 (the
11  * "License"); you may not use this file except in compliance
12  * with the License. You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing,
17  * software distributed under the License is distributed on an
18  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
19  * KIND, either express or implied. See the License for the
20  * specific language governing permissions and limitations
21  * under the License.
22  *
23  */
24 
25 #include "./fwd.hpp"
26 #include "./internal/config.hpp"
27 #include "./connection.hpp"
28 #include "./event_loop.hpp"
29 #include "./function.hpp"
30 #include "./internal/object.hpp"
31 #include "./internal/type_traits.hpp"
32 
33 #include <functional>
34 
35 namespace proton {
36 
37 namespace internal {
38 template <class T> struct endpoint_traits;
39 template<> struct endpoint_traits<connection> {};
40 template<> struct endpoint_traits<session> {};
41 template<> struct endpoint_traits<link> {};
42 template<> struct endpoint_traits<sender> {};
43 template<> struct endpoint_traits<receiver> {};
44 }
45 
62 template <class T>
63 class thread_safe : private internal::pn_ptr_base, private internal::endpoint_traits<T> {
64  typedef typename T::pn_type pn_type;
65 
66  struct inject_decref : public void_function0 {
67  pn_type* ptr_;
68  inject_decref(pn_type* p) : ptr_(p) {}
69  void operator()() PN_CPP_OVERRIDE { decref(ptr_); delete this; }
70  };
71 
72  public:
74  static void operator delete(void*) {}
76 
77  ~thread_safe() {
78  if (ptr()) {
79  if (!!event_loop()) {
80 #if PN_CPP_HAS_STD_BIND
81  event_loop().inject(std::bind(&decref, ptr()));
82 #else
83  event_loop().inject(*new inject_decref(ptr()));
84 #endif
85  } else {
86  decref(ptr());
87  }
88  }
89  }
90 
92  class event_loop& event_loop() { return event_loop::get(ptr()); }
93 
95  T unsafe() { return T(ptr()); }
96 
97  private:
98  static thread_safe* create(const T& obj) { return new (obj.pn_object()) thread_safe(); }
99  static void* operator new(size_t, pn_type* p) { return p; }
100  static void operator delete(void*, pn_type*) {}
101  thread_safe() { incref(ptr()); }
102  pn_type* ptr() { return reinterpret_cast<pn_type*>(this); }
103 
104 
105  // Non-copyable.
106  thread_safe(const thread_safe&);
107  thread_safe& operator=(const thread_safe&);
108 
110  friend class returned<T>;
112 };
113 
114 // A return value for functions returning a thread_safe<> object.
115 //
116 // Temporary return value only, you should release() to get a plain pointer or
117 // assign to a smart pointer type.
118 template <class T>
119 class returned : private internal::endpoint_traits<T>
120 {
121  public:
123  explicit returned(thread_safe<T>* p) : ptr_(p) {}
125  explicit returned(const T& obj) : ptr_(thread_safe<T>::create(obj)) {}
128  returned(const returned& x) : ptr_(const_cast<returned&>(x).release()) {}
130  ~returned() { if (ptr_) delete ptr_; }
131 
133  thread_safe<T>* release() const { thread_safe<T>* p = ptr_; ptr_ = 0; return p; }
134 
136  thread_safe<T>* get() const { return ptr_; }
137 
139  operator T() { return ptr_->unsafe(); }
140 
141 #if PN_CPP_HAS_SHARED_PTR
142  operator std::shared_ptr<thread_safe<T> >() {
144  return std::shared_ptr<thread_safe<T> >(release());
145  }
146 #endif
147 #if PN_CPP_HAS_UNIQUE_PTR
148  operator std::unique_ptr<thread_safe<T> >() {
150  return std::unique_ptr<thread_safe<T> >(release());
151  }
152 #endif
153 
154  private:
155  void operator=(const returned&);
156  mutable thread_safe<T>* ptr_;
157 };
158 
160 template <class T> returned<T> make_thread_safe(const T& obj) { return returned<T>(obj); }
161 
162 #if PN_CPP_HAS_SHARED_PTR
163 template <class T> std::shared_ptr<thread_safe<T> > make_shared_thread_safe(const T& obj) {
165  return make_thread_safe(obj);
166 }
167 #endif
168 #if PN_CPP_HAS_UNIQUE_PTR
169 template <class T> std::unique_ptr<thread_safe<T> > make_unique_thread_safe(const T& obj) {
171  return make_thread_safe(obj);
172 }
173 
174 #endif
175 
176 } // proton
177 
178 #endif // PROTON_THREAD_SAFE_HPP
class event_loop & event_loop()
Get the event loop for this object.
Definition: thread_safe.hpp:92
Experimental - A serial execution context.
Definition: event_loop.hpp:44
T unsafe()
Get the thread-unsafe proton object wrapped by this thread_safe<T>
Definition: thread_safe.hpp:95
std::shared_ptr< thread_safe< T > > make_shared_thread_safe(const T &obj)
Create a thread-safe shared_ptr to obj.
Definition: thread_safe.hpp:164
std::unique_ptr< thread_safe< T > > make_unique_thread_safe(const T &obj)
Create a thread-safe unique_ptr to obj.
Definition: thread_safe.hpp:170
returned< T > make_thread_safe(const T &obj)
Make a thread-safe wrapper for obj.
Definition: thread_safe.hpp:160
The main Proton namespace.
Definition: annotation_key.hpp:30
Experimental - A thread-safe object wrapper.
Definition: fwd.hpp:65