File indexing completed on 2025-01-18 09:29:11
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011 #ifndef BOOST_ASIO_STRAND_HPP
0012 #define BOOST_ASIO_STRAND_HPP
0013
0014 #if defined(_MSC_VER) && (_MSC_VER >= 1200)
0015 # pragma once
0016 #endif
0017
0018 #include <boost/asio/detail/config.hpp>
0019 #include <boost/asio/detail/strand_executor_service.hpp>
0020 #include <boost/asio/detail/type_traits.hpp>
0021 #include <boost/asio/execution/blocking.hpp>
0022 #include <boost/asio/execution/executor.hpp>
0023 #include <boost/asio/is_executor.hpp>
0024
0025 #include <boost/asio/detail/push_options.hpp>
0026
0027 namespace boost {
0028 namespace asio {
0029
0030
0031 template <typename Executor>
0032 class strand
0033 {
0034 public:
0035
0036 typedef Executor inner_executor_type;
0037
0038
0039
0040
0041
0042
0043 strand()
0044 : executor_(),
0045 impl_(strand::create_implementation(executor_))
0046 {
0047 }
0048
0049
0050 template <typename Executor1>
0051 explicit strand(const Executor1& e,
0052 constraint_t<
0053 conditional_t<
0054 !is_same<Executor1, strand>::value,
0055 is_convertible<Executor1, Executor>,
0056 false_type
0057 >::value
0058 > = 0)
0059 : executor_(e),
0060 impl_(strand::create_implementation(executor_))
0061 {
0062 }
0063
0064
0065 strand(const strand& other) noexcept
0066 : executor_(other.executor_),
0067 impl_(other.impl_)
0068 {
0069 }
0070
0071
0072
0073
0074
0075
0076 template <class OtherExecutor>
0077 strand(
0078 const strand<OtherExecutor>& other) noexcept
0079 : executor_(other.executor_),
0080 impl_(other.impl_)
0081 {
0082 }
0083
0084
0085 strand& operator=(const strand& other) noexcept
0086 {
0087 executor_ = other.executor_;
0088 impl_ = other.impl_;
0089 return *this;
0090 }
0091
0092
0093
0094
0095
0096
0097 template <class OtherExecutor>
0098 strand& operator=(
0099 const strand<OtherExecutor>& other) noexcept
0100 {
0101 executor_ = other.executor_;
0102 impl_ = other.impl_;
0103 return *this;
0104 }
0105
0106
0107 strand(strand&& other) noexcept
0108 : executor_(static_cast<Executor&&>(other.executor_)),
0109 impl_(static_cast<implementation_type&&>(other.impl_))
0110 {
0111 }
0112
0113
0114
0115
0116
0117
0118 template <class OtherExecutor>
0119 strand(strand<OtherExecutor>&& other) noexcept
0120 : executor_(static_cast<OtherExecutor&&>(other.executor_)),
0121 impl_(static_cast<implementation_type&&>(other.impl_))
0122 {
0123 }
0124
0125
0126 strand& operator=(strand&& other) noexcept
0127 {
0128 executor_ = static_cast<Executor&&>(other.executor_);
0129 impl_ = static_cast<implementation_type&&>(other.impl_);
0130 return *this;
0131 }
0132
0133
0134
0135
0136
0137
0138 template <class OtherExecutor>
0139 strand& operator=(strand<OtherExecutor>&& other) noexcept
0140 {
0141 executor_ = static_cast<OtherExecutor&&>(other.executor_);
0142 impl_ = static_cast<implementation_type&&>(other.impl_);
0143 return *this;
0144 }
0145
0146
0147 ~strand() noexcept
0148 {
0149 }
0150
0151
0152 inner_executor_type get_inner_executor() const noexcept
0153 {
0154 return executor_;
0155 }
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165
0166
0167
0168 template <typename Property>
0169 constraint_t<
0170 can_query<const Executor&, Property>::value,
0171 conditional_t<
0172 is_convertible<Property, execution::blocking_t>::value,
0173 execution::blocking_t,
0174 query_result_t<const Executor&, Property>
0175 >
0176 > query(const Property& p) const
0177 noexcept(is_nothrow_query<const Executor&, Property>::value)
0178 {
0179 return this->query_helper(
0180 is_convertible<Property, execution::blocking_t>(), p);
0181 }
0182
0183
0184
0185
0186
0187
0188
0189
0190
0191
0192
0193 template <typename Property>
0194 constraint_t<
0195 can_require<const Executor&, Property>::value
0196 && !is_convertible<Property, execution::blocking_t::always_t>::value,
0197 strand<decay_t<require_result_t<const Executor&, Property>>>
0198 > require(const Property& p) const
0199 noexcept(is_nothrow_require<const Executor&, Property>::value)
0200 {
0201 return strand<decay_t<require_result_t<const Executor&, Property>>>(
0202 boost::asio::require(executor_, p), impl_);
0203 }
0204
0205
0206
0207
0208
0209
0210
0211
0212
0213
0214
0215 template <typename Property>
0216 constraint_t<
0217 can_prefer<const Executor&, Property>::value
0218 && !is_convertible<Property, execution::blocking_t::always_t>::value,
0219 strand<decay_t<prefer_result_t<const Executor&, Property>>>
0220 > prefer(const Property& p) const
0221 noexcept(is_nothrow_prefer<const Executor&, Property>::value)
0222 {
0223 return strand<decay_t<prefer_result_t<const Executor&, Property>>>(
0224 boost::asio::prefer(executor_, p), impl_);
0225 }
0226
0227 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0228
0229 execution_context& context() const noexcept
0230 {
0231 return executor_.context();
0232 }
0233
0234
0235
0236
0237
0238 void on_work_started() const noexcept
0239 {
0240 executor_.on_work_started();
0241 }
0242
0243
0244
0245
0246
0247 void on_work_finished() const noexcept
0248 {
0249 executor_.on_work_finished();
0250 }
0251 #endif
0252
0253
0254
0255
0256
0257
0258
0259
0260
0261
0262
0263 template <typename Function>
0264 constraint_t<
0265 traits::execute_member<const Executor&, Function>::is_valid,
0266 void
0267 > execute(Function&& f) const
0268 {
0269 detail::strand_executor_service::execute(impl_,
0270 executor_, static_cast<Function&&>(f));
0271 }
0272
0273 #if !defined(BOOST_ASIO_NO_TS_EXECUTORS)
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289 template <typename Function, typename Allocator>
0290 void dispatch(Function&& f, const Allocator& a) const
0291 {
0292 detail::strand_executor_service::dispatch(impl_,
0293 executor_, static_cast<Function&&>(f), a);
0294 }
0295
0296
0297
0298
0299
0300
0301
0302
0303
0304
0305
0306
0307
0308
0309 template <typename Function, typename Allocator>
0310 void post(Function&& f, const Allocator& a) const
0311 {
0312 detail::strand_executor_service::post(impl_,
0313 executor_, static_cast<Function&&>(f), a);
0314 }
0315
0316
0317
0318
0319
0320
0321
0322
0323
0324
0325
0326
0327
0328
0329 template <typename Function, typename Allocator>
0330 void defer(Function&& f, const Allocator& a) const
0331 {
0332 detail::strand_executor_service::defer(impl_,
0333 executor_, static_cast<Function&&>(f), a);
0334 }
0335 #endif
0336
0337
0338
0339
0340
0341
0342
0343 bool running_in_this_thread() const noexcept
0344 {
0345 return detail::strand_executor_service::running_in_this_thread(impl_);
0346 }
0347
0348
0349
0350
0351
0352
0353 friend bool operator==(const strand& a, const strand& b) noexcept
0354 {
0355 return a.impl_ == b.impl_;
0356 }
0357
0358
0359
0360
0361
0362
0363 friend bool operator!=(const strand& a, const strand& b) noexcept
0364 {
0365 return a.impl_ != b.impl_;
0366 }
0367
0368 #if defined(GENERATING_DOCUMENTATION)
0369 private:
0370 #endif
0371 typedef detail::strand_executor_service::implementation_type
0372 implementation_type;
0373
0374 template <typename InnerExecutor>
0375 static implementation_type create_implementation(const InnerExecutor& ex,
0376 constraint_t<
0377 can_query<InnerExecutor, execution::context_t>::value
0378 > = 0)
0379 {
0380 return use_service<detail::strand_executor_service>(
0381 boost::asio::query(ex, execution::context)).create_implementation();
0382 }
0383
0384 template <typename InnerExecutor>
0385 static implementation_type create_implementation(const InnerExecutor& ex,
0386 constraint_t<
0387 !can_query<InnerExecutor, execution::context_t>::value
0388 > = 0)
0389 {
0390 return use_service<detail::strand_executor_service>(
0391 ex.context()).create_implementation();
0392 }
0393
0394 strand(const Executor& ex, const implementation_type& impl)
0395 : executor_(ex),
0396 impl_(impl)
0397 {
0398 }
0399
0400 template <typename Property>
0401 query_result_t<const Executor&, Property> query_helper(
0402 false_type, const Property& property) const
0403 {
0404 return boost::asio::query(executor_, property);
0405 }
0406
0407 template <typename Property>
0408 execution::blocking_t query_helper(true_type, const Property& property) const
0409 {
0410 execution::blocking_t result = boost::asio::query(executor_, property);
0411 return result == execution::blocking.always
0412 ? execution::blocking.possibly : result;
0413 }
0414
0415 Executor executor_;
0416 implementation_type impl_;
0417 };
0418
0419
0420
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431
0432 template <typename Executor>
0433 inline strand<Executor> make_strand(const Executor& ex,
0434 constraint_t<
0435 is_executor<Executor>::value || execution::is_executor<Executor>::value
0436 > = 0)
0437 {
0438 return strand<Executor>(ex);
0439 }
0440
0441
0442
0443
0444
0445
0446
0447
0448 template <typename ExecutionContext>
0449 inline strand<typename ExecutionContext::executor_type>
0450 make_strand(ExecutionContext& ctx,
0451 constraint_t<
0452 is_convertible<ExecutionContext&, execution_context&>::value
0453 > = 0)
0454 {
0455 return strand<typename ExecutionContext::executor_type>(ctx.get_executor());
0456 }
0457
0458
0459
0460 #if !defined(GENERATING_DOCUMENTATION)
0461
0462 namespace traits {
0463
0464 #if !defined(BOOST_ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
0465
0466 template <typename Executor>
0467 struct equality_comparable<strand<Executor>>
0468 {
0469 static constexpr bool is_valid = true;
0470 static constexpr bool is_noexcept = true;
0471 };
0472
0473 #endif
0474
0475 #if !defined(BOOST_ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
0476
0477 template <typename Executor, typename Function>
0478 struct execute_member<strand<Executor>, Function,
0479 enable_if_t<
0480 traits::execute_member<const Executor&, Function>::is_valid
0481 >>
0482 {
0483 static constexpr bool is_valid = true;
0484 static constexpr bool is_noexcept = false;
0485 typedef void result_type;
0486 };
0487
0488 #endif
0489
0490 #if !defined(BOOST_ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
0491
0492 template <typename Executor, typename Property>
0493 struct query_member<strand<Executor>, Property,
0494 enable_if_t<
0495 can_query<const Executor&, Property>::value
0496 >>
0497 {
0498 static constexpr bool is_valid = true;
0499 static constexpr bool is_noexcept =
0500 is_nothrow_query<Executor, Property>::value;
0501 typedef conditional_t<
0502 is_convertible<Property, execution::blocking_t>::value,
0503 execution::blocking_t, query_result_t<Executor, Property>> result_type;
0504 };
0505
0506 #endif
0507
0508 #if !defined(BOOST_ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
0509
0510 template <typename Executor, typename Property>
0511 struct require_member<strand<Executor>, Property,
0512 enable_if_t<
0513 can_require<const Executor&, Property>::value
0514 && !is_convertible<Property, execution::blocking_t::always_t>::value
0515 >>
0516 {
0517 static constexpr bool is_valid = true;
0518 static constexpr bool is_noexcept =
0519 is_nothrow_require<Executor, Property>::value;
0520 typedef strand<decay_t<require_result_t<Executor, Property>>> result_type;
0521 };
0522
0523 #endif
0524
0525 #if !defined(BOOST_ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
0526
0527 template <typename Executor, typename Property>
0528 struct prefer_member<strand<Executor>, Property,
0529 enable_if_t<
0530 can_prefer<const Executor&, Property>::value
0531 && !is_convertible<Property, execution::blocking_t::always_t>::value
0532 >>
0533 {
0534 static constexpr bool is_valid = true;
0535 static constexpr bool is_noexcept =
0536 is_nothrow_prefer<Executor, Property>::value;
0537 typedef strand<decay_t<prefer_result_t<Executor, Property>>> result_type;
0538 };
0539
0540 #endif
0541
0542 }
0543
0544 #endif
0545
0546 }
0547 }
0548
0549 #include <boost/asio/detail/pop_options.hpp>
0550
0551
0552
0553 #if !defined(BOOST_ASIO_NO_EXTENSIONS)
0554 # if defined(BOOST_ASIO_IO_CONTEXT_HPP)
0555 # include <boost/asio/io_context_strand.hpp>
0556 # endif
0557 #endif
0558
0559 #endif