File indexing completed on 2025-01-18 09:28:58
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_IMPL_THREAD_POOL_HPP
0012 #define BOOST_ASIO_IMPL_THREAD_POOL_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/blocking_executor_op.hpp>
0019 #include <boost/asio/detail/executor_op.hpp>
0020 #include <boost/asio/detail/fenced_block.hpp>
0021 #include <boost/asio/detail/non_const_lvalue.hpp>
0022 #include <boost/asio/detail/type_traits.hpp>
0023 #include <boost/asio/execution_context.hpp>
0024
0025 #include <boost/asio/detail/push_options.hpp>
0026
0027 namespace boost {
0028 namespace asio {
0029
0030 inline thread_pool::executor_type
0031 thread_pool::get_executor() noexcept
0032 {
0033 return executor_type(*this);
0034 }
0035
0036 inline thread_pool::executor_type
0037 thread_pool::executor() noexcept
0038 {
0039 return executor_type(*this);
0040 }
0041
0042 template <typename Allocator, unsigned int Bits>
0043 thread_pool::basic_executor_type<Allocator, Bits>&
0044 thread_pool::basic_executor_type<Allocator, Bits>::operator=(
0045 const basic_executor_type& other) noexcept
0046 {
0047 if (this != &other)
0048 {
0049 thread_pool* old_thread_pool = pool_;
0050 pool_ = other.pool_;
0051 allocator_ = other.allocator_;
0052 bits_ = other.bits_;
0053 if (Bits & outstanding_work_tracked)
0054 {
0055 if (pool_)
0056 pool_->scheduler_.work_started();
0057 if (old_thread_pool)
0058 old_thread_pool->scheduler_.work_finished();
0059 }
0060 }
0061 return *this;
0062 }
0063
0064 template <typename Allocator, unsigned int Bits>
0065 thread_pool::basic_executor_type<Allocator, Bits>&
0066 thread_pool::basic_executor_type<Allocator, Bits>::operator=(
0067 basic_executor_type&& other) noexcept
0068 {
0069 if (this != &other)
0070 {
0071 thread_pool* old_thread_pool = pool_;
0072 pool_ = other.pool_;
0073 allocator_ = std::move(other.allocator_);
0074 bits_ = other.bits_;
0075 if (Bits & outstanding_work_tracked)
0076 {
0077 other.pool_ = 0;
0078 if (old_thread_pool)
0079 old_thread_pool->scheduler_.work_finished();
0080 }
0081 }
0082 return *this;
0083 }
0084
0085 template <typename Allocator, unsigned int Bits>
0086 inline bool thread_pool::basic_executor_type<Allocator,
0087 Bits>::running_in_this_thread() const noexcept
0088 {
0089 return pool_->scheduler_.can_dispatch();
0090 }
0091
0092 template <typename Allocator, unsigned int Bits>
0093 template <typename Function>
0094 void thread_pool::basic_executor_type<Allocator,
0095 Bits>::do_execute(Function&& f, false_type) const
0096 {
0097 typedef decay_t<Function> function_type;
0098
0099
0100
0101 if ((bits_ & blocking_never) == 0 && pool_->scheduler_.can_dispatch())
0102 {
0103
0104 function_type tmp(static_cast<Function&&>(f));
0105
0106 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0107 try
0108 {
0109 #endif
0110 detail::fenced_block b(detail::fenced_block::full);
0111 static_cast<function_type&&>(tmp)();
0112 return;
0113 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0114 }
0115 catch (...)
0116 {
0117 pool_->scheduler_.capture_current_exception();
0118 return;
0119 }
0120 #endif
0121 }
0122
0123
0124 typedef detail::executor_op<function_type, Allocator> op;
0125 typename op::ptr p = { detail::addressof(allocator_),
0126 op::ptr::allocate(allocator_), 0 };
0127 p.p = new (p.v) op(static_cast<Function&&>(f), allocator_);
0128
0129 if ((bits_ & relationship_continuation) != 0)
0130 {
0131 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0132 "thread_pool", pool_, 0, "execute(blk=never,rel=cont)"));
0133 }
0134 else
0135 {
0136 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0137 "thread_pool", pool_, 0, "execute(blk=never,rel=fork)"));
0138 }
0139
0140 pool_->scheduler_.post_immediate_completion(p.p,
0141 (bits_ & relationship_continuation) != 0);
0142 p.v = p.p = 0;
0143 }
0144
0145 template <typename Allocator, unsigned int Bits>
0146 template <typename Function>
0147 void thread_pool::basic_executor_type<Allocator,
0148 Bits>::do_execute(Function&& f, true_type) const
0149 {
0150
0151 detail::non_const_lvalue<Function> f2(f);
0152
0153
0154 if (pool_->scheduler_.can_dispatch())
0155 {
0156 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0157 try
0158 {
0159 #endif
0160 detail::fenced_block b(detail::fenced_block::full);
0161 static_cast<decay_t<Function>&&>(f2.value)();
0162 return;
0163 #if !defined(BOOST_ASIO_NO_EXCEPTIONS)
0164 }
0165 catch (...)
0166 {
0167 std::terminate();
0168 }
0169 #endif
0170 }
0171
0172
0173 typedef decay_t<Function> function_type;
0174 detail::blocking_executor_op<function_type> op(f2.value);
0175
0176 BOOST_ASIO_HANDLER_CREATION((*pool_, op,
0177 "thread_pool", pool_, 0, "execute(blk=always)"));
0178
0179 pool_->scheduler_.post_immediate_completion(&op, false);
0180 op.wait();
0181 }
0182
0183 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0184 template <typename Allocator, unsigned int Bits>
0185 inline thread_pool& thread_pool::basic_executor_type<
0186 Allocator, Bits>::context() const noexcept
0187 {
0188 return *pool_;
0189 }
0190
0191 template <typename Allocator, unsigned int Bits>
0192 inline void thread_pool::basic_executor_type<Allocator,
0193 Bits>::on_work_started() const noexcept
0194 {
0195 pool_->scheduler_.work_started();
0196 }
0197
0198 template <typename Allocator, unsigned int Bits>
0199 inline void thread_pool::basic_executor_type<Allocator,
0200 Bits>::on_work_finished() const noexcept
0201 {
0202 pool_->scheduler_.work_finished();
0203 }
0204
0205 template <typename Allocator, unsigned int Bits>
0206 template <typename Function, typename OtherAllocator>
0207 void thread_pool::basic_executor_type<Allocator, Bits>::dispatch(
0208 Function&& f, const OtherAllocator& a) const
0209 {
0210 typedef decay_t<Function> function_type;
0211
0212
0213 if (pool_->scheduler_.can_dispatch())
0214 {
0215
0216 function_type tmp(static_cast<Function&&>(f));
0217
0218 detail::fenced_block b(detail::fenced_block::full);
0219 static_cast<function_type&&>(tmp)();
0220 return;
0221 }
0222
0223
0224 typedef detail::executor_op<function_type, OtherAllocator> op;
0225 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0226 p.p = new (p.v) op(static_cast<Function&&>(f), a);
0227
0228 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0229 "thread_pool", pool_, 0, "dispatch"));
0230
0231 pool_->scheduler_.post_immediate_completion(p.p, false);
0232 p.v = p.p = 0;
0233 }
0234
0235 template <typename Allocator, unsigned int Bits>
0236 template <typename Function, typename OtherAllocator>
0237 void thread_pool::basic_executor_type<Allocator, Bits>::post(
0238 Function&& f, const OtherAllocator& a) const
0239 {
0240 typedef decay_t<Function> function_type;
0241
0242
0243 typedef detail::executor_op<function_type, OtherAllocator> op;
0244 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0245 p.p = new (p.v) op(static_cast<Function&&>(f), a);
0246
0247 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0248 "thread_pool", pool_, 0, "post"));
0249
0250 pool_->scheduler_.post_immediate_completion(p.p, false);
0251 p.v = p.p = 0;
0252 }
0253
0254 template <typename Allocator, unsigned int Bits>
0255 template <typename Function, typename OtherAllocator>
0256 void thread_pool::basic_executor_type<Allocator, Bits>::defer(
0257 Function&& f, const OtherAllocator& a) const
0258 {
0259 typedef decay_t<Function> function_type;
0260
0261
0262 typedef detail::executor_op<function_type, OtherAllocator> op;
0263 typename op::ptr p = { detail::addressof(a), op::ptr::allocate(a), 0 };
0264 p.p = new (p.v) op(static_cast<Function&&>(f), a);
0265
0266 BOOST_ASIO_HANDLER_CREATION((*pool_, *p.p,
0267 "thread_pool", pool_, 0, "defer"));
0268
0269 pool_->scheduler_.post_immediate_completion(p.p, true);
0270 p.v = p.p = 0;
0271 }
0272 #endif
0273
0274 }
0275 }
0276
0277 #include <boost/asio/detail/pop_options.hpp>
0278
0279 #endif