mirror of
https://github.com/zhenyan121/Cubed.git
synced 2026-08-09 02:07:04 +08:00
* build: add asio library * feat(dev_panel): add Asio to about table * refactor(gameplay): split Chunk into server/client variants and add networking * feat(gameplay): add Session class and UUID generation utility * feat(network): integrate protobuf for player sync and session management Add Protobuf dependency, define proto messages for player requests, positions, and chunk data. Refactor Session to use strand and async write. Implement player join/exit and position sync in ServerWorld. * refactor(proto): restructure protobuf definitions and update build system * feat(protocol): add packet serialization and login handling Introduce packet header and ID mapping for protobuf messages. Refactor session and server_world to use new packet wrapper. Fix missing semicolons in proto files. * refactor(packet): serialize directly into packet buffer with ByteSizeLong * feat(world): add player-based chunk loading and UUID support Restructure world generation to trigger chunk loading based on player movement. Replace player name with UUID for identification. Implement chunk request/response protocol. Improve thread management for gen thread. * feat(server): add block change packet handling and increase reserved threads * refactor(server): enhance thread safety and session management * fix(session): catch std::exception in read_loop and log error * fix(network-server): stop accept loop on shutdown flag * fix(gameplay): correct unknown error log condition and missing chunk pos update * feat(client): add client-side chunk, player, world and network classes * feat(client-chunk): add greedy meshing, receive_chunk, and biome field * feat(client_player): add name constructor param, remove chunk transition * feat(gameplay): integrate network client and thread-safe player pos * feat(gameplay): add block change sync and coordinate utils * refactor(server): replace Chunk with ServerChunk * refactor(gameplay): split world into client and server Remove monolithic World, Player, Chunk classes. Introduce ClientWorld, ServerWorld, ClientPlayer, and related networked components. Add Abseil dependency for logging and checks. Rename old files to pre_remove_* and update all includes and references accordingly. * feat(gameplay): add time sync and network improvements * fix: correct neighbor block indexing and add time update support * feat(gameplay): optimize chunk request with player chunk tracking Add `update_player_chunk()` method to `ClientPlayer` that triggers a chunk request when the player moves more than 2 chunks away from the last recorded chunk. Introduce an atomic `m_requesting_chunk` flag in `ClientWorld` to prevent concurrent requests. Rename `m_player_chunk_pos` to `m_last_chunk_pos` for clarity. * refactor(client_world): split pending queue into data and upload queues * feat(client): add center-based chunk loading priority * feat(app): add client/server CLI arguments and init guards * feat(multiplayer): add rendering of other players as colored cubes * feat(gameplay): add thread pool for asynchronous chunk data processing * feat(gameplay): add player logout and disconnect handling * fix(dev_panel): add protobuf to about table libraries * build: add ZLIB dependency * refactor(packet): replace zlib with zstd compression and restructure header Increase header length to 12 bytes, add CompressType and PacketHeader struct, and implement decode_packet_header. Update CMake to find zstd and link against it, adding Findzstd module. * refactor(network): extract packet header decoding into function * feat(packet): implement zstd compression and refactor packet decoding * perf(gameplay): optimize protobuf message allocation with Arena and limit thread pool size Switch to Arena allocation for protobuf messages to reduce heap allocations. Pass ChunkDataRsp by value to enable move semantics. Cap thread pool size to hardware concurrency with max 4 threads. * refactor(gameplay): use steady clock and sleep_until for tick loop timing * refactor(gameplay): rename remote player types and add interpolation * refactor(server_world): use thread pool for chunk request handling * refactor(packet): replace if-constexpr chain with explicit template specializations Refactor `get_packet_id()` by removing the if-constexpr chain and instead providing explicit specializations for each packet type. This simplifies the primary template (which now only contains a static assertion) and improves compile-time dispatch clarity. The `always_false` helper is no longer needed in the primary template. * feat(gameplay): add packet to clear all chunks on server rebuild Add new packet S2C_ClearAllChunks (ID 3005) to notify clients when the server rebuilds its world. Clients respond by clearing their chunk cache and requesting fresh chunks. Shift UPDATE_TIME packet ID to 3006 to accommodate. * feat(dev_panel): split world tab; add chunk request logging and fix flag reset * feat(tools): add RecentQueue to replace std::deque in server_world * feat(gameplay): add task ID to chunk requests to discard stale responses * refactor(block): move block source to gameplay directory * feat(toml): add shared TOML utilities and handle ip.toml * feat: add player name configuration and rename config file - Add --player command-line argument and 'player' field in Arguments struct - Rename ip.toml to server.toml and corresponding internal variable to 'server' - Fix block.cpp source path in CMakeLists.txt * build(cmake): modularize build configuration * fix: build fail on windows * refactor(renderer): rename Logger level enum value DEBUG to L_DEBUG * refactor(world): rework chunk state machine and player chunk tracking Introduce ChunkState enum and ChunkEntity struct to manage chunk lifecycle. Store chunks as shared_ptr to avoid move operations during generation. Add clear_unused_chunks to remove chunks not referenced by any player. Implement deferred chunk request queue for safe processing after generation completes. Update player chunk set during required chunk computation. Improve thread safety with mutexes on chunk and player maps. Fix m_gening flag not reset after generation and add assertions for correctness. Change need_gen to require a player UUID, removing std::optional. Add chunk_size query method for debugging. * fix(server): ensure chunk is ready before sending or setting block * refactor(server_world): separate gen and net thread pools Introduce a second thread pool for network operations and a `ThreadPoolKind` enum to distinguish between gen and net pools. Rename `pool_threads()` to `gen_pool_threads()`, add `change_pool_threads()` overload that accepts the pool kind, and update the dev panel to use the gen pool. Adjust logging and initialization to handle both pools. * feat(client_world): implement server exit acknowledgment with timeout * feat(gameplay): implement server stop and client exit handling Add server_stop flag to LogoutRsp protocol. Modify client_world to check for server stop or own logout to set exit flag. Add ServerWorld::stop() to broadcast stop and cleanly shut down. Refactor chunk ownership to unique_ptr. Remove name parameter from get_look_block_pos. * fix(app): correct port validation and remove redundant TOML helper * fix: address unused parameter warnings and missing port assignment * refactor(gameplay): remove old pre_remove chunk, player, and world files * refactor(server): replace chunk set with flat_hash_set and add ref count - Replace std::unordered_set with absl::flat_hash_set for chunk position sets. - Add ref_count field to ChunkEntity and implement update_ref_count(). - Remove clear_unused_chunks() and use ref counting for chunk lifetime. - Add get_chunk_pos_set() accessors to ServerPlayer. * fix(client-world): delay chunk request to wait for server central chunk generation * refactor(gameplay): migrate chunk storage to tbb::concurrent_hash_map * refactor(server_world): replace future-based chunk generation with queue Remove `std::future` per-chunk tracking and poll_finished_chunks(). Instead, generation tasks push completed chunks to a concurrent queue consumed during update. This eliminates wait_all_chunk_tasks() and simplifies synchronization. * refactor(client_world): use concurrent data structures for chunk management Replace std::shared_mutex and std::unordered_set with tbb::concurrent_hash_map for chunk storage, tbb::concurrent_queue for pending uploads, and absl::flat_hash_set for player chunk positions. This improves thread safety and reduces locking overhead. Refactor receive_chunk and request_chunk to work with the new concurrent model. * build(windows): add Nvidia and AMD GPU high performance exports * fix(ci): update header file pattern in clang-format check * style(clang-format): comment out AlignPPAndNotPP option * chore: enable AlignPPAndNotPP in clang-format and pin clang version in CI * ci(workflow): update format check to use LLVM 22 * ci(format-check): install clang-format-22 * perf(world): cull distant players from updates and rendering Add distance2 utility function. On client, skip rendering other players if distance squared exceeds rendering distance. On server, only send player position and block change updates to players in relevant chunks. * refactor(math_tools): convert free functions to inline in header * refactor(dev_panel): remove seed editing and server rebuild world, move client rebuild - Remove text editing for perlin seed and filter function - Remove ServerWorld::rebuild_world() method and its atomic flag - Move 'Rebuild World' button to client world tab - Remove unused perlin_noise_input_buffer * fix(server_world): floor block position coordinates in handle_block_change * refactor(gameplay): pass new_chunks vector as parameter instead of member variable * perf(client): improve chunk rendering performance with snapshots and threaded generation * feat(tools): add PriorityThreadPool with priority scheduling Implement PriorityThreadPool supporting task priorities and FIFO ordering for same priority. Update ClientWorld to use the new pool with explicit priority for chunk operations. Fix ThreadPool stop logic with atomic exchange and remove unnecessary lambda capture. * feat(networking): add priority and sequence ordering to packet send queues * feat(server-world): use priority thread pool for chunk generation Introduce PriorityThreadPool to process chunk generation tasks with priorities based on their distance from the player. Closer chunks receive higher priority, improving responsiveness. * refactor(client): extract AABB creation and add collision check on block place Make ClientPlayer::get_aabb and ClientWorld::get_block_aabb static. Change player size to static constexpr M_SIZE. Use shared_mutex for concurrent reads of other players. Check for collision with other players before placing a block. * feat(build): add build-time version system via CMake configure_file * ci(release): add release build workflow for windows
1086 lines
34 KiB
C++
1086 lines
34 KiB
C++
//
|
|
// thread_pool.hpp
|
|
// ~~~~~~~~~~~~~~~
|
|
//
|
|
// Copyright (c) 2003-2026 Christopher M. Kohlhoff (chris at kohlhoff dot com)
|
|
//
|
|
// Distributed under the Boost Software License, Version 1.0. (See accompanying
|
|
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
|
|
//
|
|
|
|
#ifndef ASIO_THREAD_POOL_HPP
|
|
#define ASIO_THREAD_POOL_HPP
|
|
|
|
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
# pragma once
|
|
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
|
|
|
|
#include "asio/detail/config.hpp"
|
|
#include "asio/detail/atomic_count.hpp"
|
|
#include "asio/detail/scheduler.hpp"
|
|
#include "asio/detail/thread_group.hpp"
|
|
#include "asio/execution.hpp"
|
|
#include "asio/execution_context.hpp"
|
|
|
|
#include "asio/detail/push_options.hpp"
|
|
|
|
namespace asio {
|
|
ASIO_INLINE_NAMESPACE_BEGIN
|
|
namespace detail {
|
|
struct thread_pool_bits
|
|
{
|
|
static constexpr unsigned int blocking_never = 1;
|
|
static constexpr unsigned int blocking_always = 2;
|
|
static constexpr unsigned int blocking_mask = 3;
|
|
static constexpr unsigned int relationship_continuation = 4;
|
|
static constexpr unsigned int outstanding_work_tracked = 8;
|
|
};
|
|
} // namespace detail
|
|
|
|
/// A simple fixed-size thread pool.
|
|
/**
|
|
* The thread pool class is an execution context where functions are permitted
|
|
* to run on one of a fixed number of threads.
|
|
*
|
|
* @par Thread Safety
|
|
* @e Distinct @e objects: Safe.@n
|
|
* @e Shared @e objects: Safe, with the specific exceptions of the join()
|
|
* wait() and notify_fork() functions. The join() and wait() functions must not
|
|
* be called at the same time as other calls to join() or wait() on the same
|
|
* pool. The notify_fork() function should not be called while any thread_pool
|
|
* function, or any function on an I/O object that is associated with the
|
|
* thread_pool, is being called in another thread. (In effect, this means that
|
|
* notify_fork() is safe only on a thread pool that has no internal or attached
|
|
* threads at the time.)
|
|
*
|
|
* @par Submitting tasks to the pool
|
|
*
|
|
* To submit functions to the thread pool, use the @ref asio::dispatch,
|
|
* @ref asio::post or @ref asio::defer free functions.
|
|
*
|
|
* For example:
|
|
*
|
|
* @code void my_task()
|
|
* {
|
|
* ...
|
|
* }
|
|
*
|
|
* ...
|
|
*
|
|
* // Launch the pool with four threads.
|
|
* asio::thread_pool pool(4);
|
|
*
|
|
* // Submit a function to the pool.
|
|
* asio::post(pool, my_task);
|
|
*
|
|
* // Submit a lambda object to the pool.
|
|
* asio::post(pool,
|
|
* []()
|
|
* {
|
|
* ...
|
|
* });
|
|
*
|
|
* // Wait for all tasks in the pool to complete.
|
|
* pool.join(); @endcode
|
|
*/
|
|
class thread_pool
|
|
: public execution_context
|
|
{
|
|
public:
|
|
template <typename Allocator, unsigned int Bits>
|
|
class basic_executor_type;
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
friend class basic_executor_type;
|
|
|
|
/// Executor used to submit functions to a thread pool.
|
|
typedef basic_executor_type<std::allocator<void>, 0> executor_type;
|
|
|
|
#if !defined(ASIO_NO_TS_EXECUTORS)
|
|
/// Constructs a pool with an automatically determined number of threads.
|
|
ASIO_DECL thread_pool();
|
|
|
|
/// Constructs a pool with an automatically determined number of threads.
|
|
/**
|
|
* @param a An allocator that will be used for allocating objects that are
|
|
* associated with the execution context, such as services and internal state
|
|
* for I/O objects.
|
|
*/
|
|
template <typename Allocator>
|
|
thread_pool(allocator_arg_t, const Allocator& a);
|
|
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
|
|
|
/// Constructs a pool with a specified number of threads.
|
|
/**
|
|
* @param num_threads The number of threads required.
|
|
*/
|
|
ASIO_DECL explicit thread_pool(std::size_t num_threads);
|
|
|
|
/// Constructs a pool with a specified number of threads.
|
|
/**
|
|
* @param num_threads The number of threads required.
|
|
*
|
|
* @param a An allocator that will be used for allocating objects that are
|
|
* associated with the execution context, such as services and internal state
|
|
* for I/O objects.
|
|
*/
|
|
template <typename Allocator>
|
|
thread_pool(allocator_arg_t, const Allocator& a, std::size_t num_threads);
|
|
|
|
/// Constructs a pool with a specified number of threads.
|
|
/**
|
|
* Construct with a service maker, to create an initial set of services that
|
|
* will be installed into the execution context at construction time.
|
|
*
|
|
* @param num_threads The number of threads required.
|
|
*
|
|
* @param initial_services Used to create the initial services. The @c make
|
|
* function will be called once at the end of execution_context construction.
|
|
*/
|
|
ASIO_DECL thread_pool(std::size_t num_threads,
|
|
const execution_context::service_maker& initial_services);
|
|
|
|
/// Constructs a pool with a specified number of threads.
|
|
/**
|
|
* Construct with a service maker, to create an initial set of services that
|
|
* will be installed into the execution context at construction time.
|
|
*
|
|
* @param a An allocator that will be used for allocating objects that are
|
|
* associated with the execution context, such as services and internal state
|
|
* for I/O objects.
|
|
*
|
|
* @param num_threads The number of threads required.
|
|
*
|
|
* @param initial_services Used to create the initial services. The @c make
|
|
* function will be called once at the end of execution_context construction.
|
|
*/
|
|
template <typename Allocator>
|
|
thread_pool(allocator_arg_t, const Allocator& a, std::size_t num_threads,
|
|
const execution_context::service_maker& initial_services);
|
|
|
|
/// Destructor.
|
|
/**
|
|
* Automatically stops and joins the pool, if not explicitly done beforehand.
|
|
*/
|
|
ASIO_DECL ~thread_pool();
|
|
|
|
/// Obtains the executor associated with the pool.
|
|
executor_type get_executor() noexcept;
|
|
|
|
/// Obtains the executor associated with the pool.
|
|
executor_type executor() noexcept;
|
|
|
|
/// Stops the threads.
|
|
/**
|
|
* This function stops the threads as soon as possible. As a result of calling
|
|
* @c stop(), pending function objects may be never be invoked.
|
|
*/
|
|
ASIO_DECL void stop();
|
|
|
|
/// Attaches the current thread to the pool.
|
|
/**
|
|
* This function attaches the current thread to the pool so that it may be
|
|
* used for executing submitted function objects. Blocks the calling thread
|
|
* until the pool is stopped or joined and has no outstanding work.
|
|
*/
|
|
ASIO_DECL void attach();
|
|
|
|
/// Joins the threads.
|
|
/**
|
|
* This function blocks until the threads in the pool have completed. If @c
|
|
* stop() is not called prior to @c join(), the @c join() call will wait
|
|
* until the pool has no more outstanding work.
|
|
*/
|
|
ASIO_DECL void join();
|
|
|
|
/// Waits for threads to complete.
|
|
/**
|
|
* This function blocks until the threads in the pool have completed. If @c
|
|
* stop() is not called prior to @c wait(), the @c wait() call will wait
|
|
* until the pool has no more outstanding work.
|
|
*
|
|
* @note @c wait() is synonymous with @c join().
|
|
*/
|
|
ASIO_DECL void wait();
|
|
|
|
private:
|
|
thread_pool(const thread_pool&) = delete;
|
|
thread_pool& operator=(const thread_pool&) = delete;
|
|
|
|
struct thread_function;
|
|
|
|
#if !defined(ASIO_NO_TS_EXECUTORS)
|
|
// Helper function to calculate the default number of threads in the pool.
|
|
ASIO_DECL static long default_thread_pool_size();
|
|
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
|
|
|
// Helper function to ensure the thread pool size is not out of range.
|
|
ASIO_DECL static long clamp_thread_pool_size(std::size_t n);
|
|
|
|
// Helper function to start all threads in the pool.
|
|
ASIO_DECL void start();
|
|
|
|
// The underlying scheduler.
|
|
detail::scheduler& scheduler_;
|
|
|
|
// The threads in the pool.
|
|
detail::thread_group<allocator<void>> threads_;
|
|
|
|
// The current number of threads in the pool.
|
|
detail::atomic_count num_threads_;
|
|
|
|
// Whether a join call will have any effect.
|
|
bool joinable_;
|
|
};
|
|
|
|
/// Executor implementation type used to submit functions to a thread pool.
|
|
template <typename Allocator, unsigned int Bits>
|
|
class thread_pool::basic_executor_type : detail::thread_pool_bits
|
|
{
|
|
public:
|
|
/// Copy constructor.
|
|
basic_executor_type(const basic_executor_type& other) noexcept
|
|
: pool_(other.pool_),
|
|
allocator_(other.allocator_),
|
|
bits_(other.bits_)
|
|
{
|
|
if (Bits & outstanding_work_tracked)
|
|
if (pool_)
|
|
pool_->scheduler_.work_started();
|
|
}
|
|
|
|
/// Move constructor.
|
|
basic_executor_type(basic_executor_type&& other) noexcept
|
|
: pool_(other.pool_),
|
|
allocator_(static_cast<Allocator&&>(other.allocator_)),
|
|
bits_(other.bits_)
|
|
{
|
|
if (Bits & outstanding_work_tracked)
|
|
other.pool_ = 0;
|
|
}
|
|
|
|
/// Destructor.
|
|
~basic_executor_type() noexcept
|
|
{
|
|
if (Bits & outstanding_work_tracked)
|
|
if (pool_)
|
|
pool_->scheduler_.work_finished();
|
|
}
|
|
|
|
/// Assignment operator.
|
|
basic_executor_type& operator=(const basic_executor_type& other) noexcept;
|
|
|
|
/// Move assignment operator.
|
|
basic_executor_type& operator=(basic_executor_type&& other) noexcept;
|
|
|
|
#if !defined(GENERATING_DOCUMENTATION)
|
|
private:
|
|
friend struct ASIO_VERSIONED_NAME(require_fn)::impl;
|
|
friend struct ASIO_VERSIONED_NAME(prefer_fn)::impl;
|
|
#endif // !defined(GENERATING_DOCUMENTATION)
|
|
|
|
/// Obtain an executor with the @c blocking.possibly property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::blocking.possibly); @endcode
|
|
*/
|
|
constexpr basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
|
|
require(execution::blocking_t::possibly_t) const
|
|
{
|
|
return basic_executor_type<Allocator, Bits & ~blocking_mask>(
|
|
pool_, allocator_, bits_ & ~blocking_mask);
|
|
}
|
|
|
|
/// Obtain an executor with the @c blocking.always property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::blocking.always); @endcode
|
|
*/
|
|
constexpr basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>
|
|
require(execution::blocking_t::always_t) const
|
|
{
|
|
return basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED((Bits & ~blocking_mask) | blocking_always)>(
|
|
pool_, allocator_, bits_ & ~blocking_mask);
|
|
}
|
|
|
|
/// Obtain an executor with the @c blocking.never property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::blocking.never); @endcode
|
|
*/
|
|
constexpr basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED(Bits & ~blocking_mask)>
|
|
require(execution::blocking_t::never_t) const
|
|
{
|
|
return basic_executor_type<Allocator, Bits & ~blocking_mask>(
|
|
pool_, allocator_, (bits_ & ~blocking_mask) | blocking_never);
|
|
}
|
|
|
|
/// Obtain an executor with the @c relationship.fork property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::relationship.fork); @endcode
|
|
*/
|
|
constexpr basic_executor_type require(execution::relationship_t::fork_t) const
|
|
{
|
|
return basic_executor_type(pool_,
|
|
allocator_, bits_ & ~relationship_continuation);
|
|
}
|
|
|
|
/// Obtain an executor with the @c relationship.continuation property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::relationship.continuation); @endcode
|
|
*/
|
|
constexpr basic_executor_type require(
|
|
execution::relationship_t::continuation_t) const
|
|
{
|
|
return basic_executor_type(pool_,
|
|
allocator_, bits_ | relationship_continuation);
|
|
}
|
|
|
|
/// Obtain an executor with the @c outstanding_work.tracked property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::outstanding_work.tracked); @endcode
|
|
*/
|
|
constexpr basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED(Bits | outstanding_work_tracked)>
|
|
require(execution::outstanding_work_t::tracked_t) const
|
|
{
|
|
return basic_executor_type<Allocator, Bits | outstanding_work_tracked>(
|
|
pool_, allocator_, bits_);
|
|
}
|
|
|
|
/// Obtain an executor with the @c outstanding_work.untracked property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::outstanding_work.untracked); @endcode
|
|
*/
|
|
constexpr basic_executor_type<Allocator,
|
|
ASIO_UNSPECIFIED(Bits & ~outstanding_work_tracked)>
|
|
require(execution::outstanding_work_t::untracked_t) const
|
|
{
|
|
return basic_executor_type<Allocator, Bits & ~outstanding_work_tracked>(
|
|
pool_, allocator_, bits_);
|
|
}
|
|
|
|
/// Obtain an executor with the specified @c allocator property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::allocator(my_allocator)); @endcode
|
|
*/
|
|
template <typename OtherAllocator>
|
|
constexpr basic_executor_type<OtherAllocator, Bits>
|
|
require(execution::allocator_t<OtherAllocator> a) const
|
|
{
|
|
return basic_executor_type<OtherAllocator, Bits>(
|
|
pool_, a.value(), bits_);
|
|
}
|
|
|
|
/// Obtain an executor with the default @c allocator property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::require customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex1 = my_thread_pool.executor();
|
|
* auto ex2 = asio::require(ex1,
|
|
* asio::execution::allocator); @endcode
|
|
*/
|
|
constexpr basic_executor_type<std::allocator<void>, Bits>
|
|
require(execution::allocator_t<void>) const
|
|
{
|
|
return basic_executor_type<std::allocator<void>, Bits>(
|
|
pool_, std::allocator<void>(), bits_);
|
|
}
|
|
|
|
#if !defined(GENERATING_DOCUMENTATION)
|
|
private:
|
|
friend struct ASIO_VERSIONED_NAME(query_fn)::impl;
|
|
friend struct asio::execution::detail::mapping_t<0>;
|
|
friend struct asio::execution::detail::inline_exception_handling_t<0>;
|
|
friend struct asio::execution::detail::outstanding_work_t<0>;
|
|
#endif // !defined(GENERATING_DOCUMENTATION)
|
|
|
|
/// Query the current value of the @c mapping property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* if (asio::query(ex, asio::execution::mapping)
|
|
* == asio::execution::mapping.thread)
|
|
* ... @endcode
|
|
*/
|
|
static constexpr execution::mapping_t query(execution::mapping_t) noexcept
|
|
{
|
|
return execution::mapping.thread;
|
|
}
|
|
|
|
/// Query the current value of the @c inline_exception_handling property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.get_executor();
|
|
* if (asio::query(ex,
|
|
* asio::execution::inline_exception_handling)
|
|
* == asio::execution::inline_exception_handling.terminate)
|
|
* ... @endcode
|
|
*/
|
|
static constexpr execution::inline_exception_handling_t query(
|
|
execution::inline_exception_handling_t) noexcept
|
|
{
|
|
return execution::inline_exception_handling.terminate;
|
|
}
|
|
|
|
/// Query the current value of the @c context property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* asio::thread_pool& pool = asio::query(
|
|
* ex, asio::execution::context); @endcode
|
|
*/
|
|
thread_pool& query(execution::context_t) const noexcept
|
|
{
|
|
return *pool_;
|
|
}
|
|
|
|
/// Query the current value of the @c blocking property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* if (asio::query(ex, asio::execution::blocking)
|
|
* == asio::execution::blocking.always)
|
|
* ... @endcode
|
|
*/
|
|
constexpr execution::blocking_t query(execution::blocking_t) const noexcept
|
|
{
|
|
return (bits_ & blocking_never)
|
|
? execution::blocking_t(execution::blocking.never)
|
|
: ((Bits & blocking_always)
|
|
? execution::blocking_t(execution::blocking.always)
|
|
: execution::blocking_t(execution::blocking.possibly));
|
|
}
|
|
|
|
/// Query the current value of the @c relationship property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* if (asio::query(ex, asio::execution::relationship)
|
|
* == asio::execution::relationship.continuation)
|
|
* ... @endcode
|
|
*/
|
|
constexpr execution::relationship_t query(
|
|
execution::relationship_t) const noexcept
|
|
{
|
|
return (bits_ & relationship_continuation)
|
|
? execution::relationship_t(execution::relationship.continuation)
|
|
: execution::relationship_t(execution::relationship.fork);
|
|
}
|
|
|
|
/// Query the current value of the @c outstanding_work property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* if (asio::query(ex, asio::execution::outstanding_work)
|
|
* == asio::execution::outstanding_work.tracked)
|
|
* ... @endcode
|
|
*/
|
|
static constexpr execution::outstanding_work_t query(
|
|
execution::outstanding_work_t) noexcept
|
|
{
|
|
return (Bits & outstanding_work_tracked)
|
|
? execution::outstanding_work_t(execution::outstanding_work.tracked)
|
|
: execution::outstanding_work_t(execution::outstanding_work.untracked);
|
|
}
|
|
|
|
/// Query the current value of the @c allocator property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* auto alloc = asio::query(ex,
|
|
* asio::execution::allocator); @endcode
|
|
*/
|
|
template <typename OtherAllocator>
|
|
constexpr Allocator query(
|
|
execution::allocator_t<OtherAllocator>) const noexcept
|
|
{
|
|
return allocator_;
|
|
}
|
|
|
|
/// Query the current value of the @c allocator property.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* auto alloc = asio::query(ex,
|
|
* asio::execution::allocator); @endcode
|
|
*/
|
|
constexpr Allocator query(execution::allocator_t<void>) const noexcept
|
|
{
|
|
return allocator_;
|
|
}
|
|
|
|
/// Query the occupancy (recommended number of work items) for the pool.
|
|
/**
|
|
* Do not call this function directly. It is intended for use with the
|
|
* asio::query customisation point.
|
|
*
|
|
* For example:
|
|
* @code auto ex = my_thread_pool.executor();
|
|
* std::size_t occupancy = asio::query(
|
|
* ex, asio::execution::occupancy); @endcode
|
|
*/
|
|
std::size_t query(execution::occupancy_t) const noexcept
|
|
{
|
|
return static_cast<std::size_t>(pool_->num_threads_);
|
|
}
|
|
|
|
public:
|
|
/// Determine whether the thread pool is running in the current thread.
|
|
/**
|
|
* @return @c true if the current thread is running the thread pool. Otherwise
|
|
* returns @c false.
|
|
*/
|
|
bool running_in_this_thread() const noexcept;
|
|
|
|
/// Compare two executors for equality.
|
|
/**
|
|
* Two executors are equal if they refer to the same underlying thread pool.
|
|
*/
|
|
friend bool operator==(const basic_executor_type& a,
|
|
const basic_executor_type& b) noexcept
|
|
{
|
|
return a.pool_ == b.pool_
|
|
&& a.allocator_ == b.allocator_
|
|
&& a.bits_ == b.bits_;
|
|
}
|
|
|
|
/// Compare two executors for inequality.
|
|
/**
|
|
* Two executors are equal if they refer to the same underlying thread pool.
|
|
*/
|
|
friend bool operator!=(const basic_executor_type& a,
|
|
const basic_executor_type& b) noexcept
|
|
{
|
|
return a.pool_ != b.pool_
|
|
|| a.allocator_ != b.allocator_
|
|
|| a.bits_ != b.bits_;
|
|
}
|
|
|
|
/// Execution function.
|
|
template <typename Function>
|
|
void execute(Function&& f) const
|
|
{
|
|
this->do_execute(static_cast<Function&&>(f),
|
|
integral_constant<bool, (Bits & blocking_always) != 0>());
|
|
}
|
|
|
|
public:
|
|
#if !defined(ASIO_NO_TS_EXECUTORS)
|
|
/// Obtain the underlying execution context.
|
|
thread_pool& context() const noexcept;
|
|
|
|
/// Inform the thread pool that it has some outstanding work to do.
|
|
/**
|
|
* This function is used to inform the thread pool that some work has begun.
|
|
* This ensures that the thread pool's join() function will not return while
|
|
* the work is underway.
|
|
*/
|
|
void on_work_started() const noexcept;
|
|
|
|
/// Inform the thread pool that some work is no longer outstanding.
|
|
/**
|
|
* This function is used to inform the thread pool that some work has
|
|
* finished. Once the count of unfinished work reaches zero, the thread
|
|
* pool's join() function is permitted to exit.
|
|
*/
|
|
void on_work_finished() const noexcept;
|
|
|
|
/// Request the thread pool to invoke the given function object.
|
|
/**
|
|
* This function is used to ask the thread pool to execute the given function
|
|
* object. If the current thread belongs to the pool, @c dispatch() executes
|
|
* the function before returning. Otherwise, the function will be scheduled
|
|
* to run on the thread pool.
|
|
*
|
|
* @param f The function object to be called. The executor will make
|
|
* a copy of the handler object as required. The function signature of the
|
|
* function object must be: @code void function(); @endcode
|
|
*
|
|
* @param a An allocator that may be used by the executor to allocate the
|
|
* internal storage needed for function invocation.
|
|
*/
|
|
template <typename Function, typename OtherAllocator>
|
|
void dispatch(Function&& f, const OtherAllocator& a) const;
|
|
|
|
/// Request the thread pool to invoke the given function object.
|
|
/**
|
|
* This function is used to ask the thread pool to execute the given function
|
|
* object. The function object will never be executed inside @c post().
|
|
* Instead, it will be scheduled to run on the thread pool.
|
|
*
|
|
* @param f The function object to be called. The executor will make
|
|
* a copy of the handler object as required. The function signature of the
|
|
* function object must be: @code void function(); @endcode
|
|
*
|
|
* @param a An allocator that may be used by the executor to allocate the
|
|
* internal storage needed for function invocation.
|
|
*/
|
|
template <typename Function, typename OtherAllocator>
|
|
void post(Function&& f, const OtherAllocator& a) const;
|
|
|
|
/// Request the thread pool to invoke the given function object.
|
|
/**
|
|
* This function is used to ask the thread pool to execute the given function
|
|
* object. The function object will never be executed inside @c defer().
|
|
* Instead, it will be scheduled to run on the thread pool.
|
|
*
|
|
* If the current thread belongs to the thread pool, @c defer() will delay
|
|
* scheduling the function object until the current thread returns control to
|
|
* the pool.
|
|
*
|
|
* @param f The function object to be called. The executor will make
|
|
* a copy of the handler object as required. The function signature of the
|
|
* function object must be: @code void function(); @endcode
|
|
*
|
|
* @param a An allocator that may be used by the executor to allocate the
|
|
* internal storage needed for function invocation.
|
|
*/
|
|
template <typename Function, typename OtherAllocator>
|
|
void defer(Function&& f, const OtherAllocator& a) const;
|
|
#endif // !defined(ASIO_NO_TS_EXECUTORS)
|
|
|
|
private:
|
|
friend class thread_pool;
|
|
template <typename, unsigned int> friend class basic_executor_type;
|
|
|
|
// Constructor used by thread_pool::get_executor().
|
|
explicit basic_executor_type(thread_pool& p) noexcept
|
|
: pool_(&p),
|
|
allocator_(),
|
|
bits_(0)
|
|
{
|
|
if (Bits & outstanding_work_tracked)
|
|
pool_->scheduler_.work_started();
|
|
}
|
|
|
|
// Constructor used by require().
|
|
basic_executor_type(thread_pool* p,
|
|
const Allocator& a, unsigned int bits) noexcept
|
|
: pool_(p),
|
|
allocator_(a),
|
|
bits_(bits)
|
|
{
|
|
if (Bits & outstanding_work_tracked)
|
|
if (pool_)
|
|
pool_->scheduler_.work_started();
|
|
}
|
|
|
|
/// Execution helper implementation for possibly and never blocking.
|
|
template <typename Function>
|
|
void do_execute(Function&& f, false_type) const;
|
|
|
|
/// Execution helper implementation for always blocking.
|
|
template <typename Function>
|
|
void do_execute(Function&& f, true_type) const;
|
|
|
|
// The underlying thread pool.
|
|
thread_pool* pool_;
|
|
|
|
// The allocator used for execution functions.
|
|
Allocator allocator_;
|
|
|
|
// The runtime-switched properties of the thread pool executor.
|
|
unsigned int bits_;
|
|
};
|
|
|
|
#if !defined(GENERATING_DOCUMENTATION)
|
|
|
|
namespace traits {
|
|
|
|
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct equality_comparable<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
};
|
|
|
|
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
|
|
|
|
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Function>
|
|
struct execute_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Function
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef void result_type;
|
|
};
|
|
|
|
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
|
|
|
|
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::blocking_t::possibly_t
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits & ~blocking_mask> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::blocking_t::always_t
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<Allocator,
|
|
(Bits & ~blocking_mask) | blocking_always> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::blocking_t::never_t
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits & ~blocking_mask> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::relationship_t::fork_t
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::relationship_t::continuation_t
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::outstanding_work_t::tracked_t
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits | outstanding_work_tracked> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::outstanding_work_t::untracked_t
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
Allocator, Bits & ~outstanding_work_tracked> result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::allocator_t<void>
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
std::allocator<void>, Bits> result_type;
|
|
};
|
|
|
|
template <unsigned int Bits,
|
|
typename Allocator, typename OtherAllocator>
|
|
struct require_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::allocator_t<OtherAllocator>
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = false;
|
|
typedef asio::thread_pool::basic_executor_type<
|
|
OtherAllocator, Bits> result_type;
|
|
};
|
|
|
|
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
|
|
|
|
#if !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Property>
|
|
struct query_static_constexpr_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Property,
|
|
typename asio::enable_if<
|
|
asio::is_convertible<
|
|
Property,
|
|
asio::execution::outstanding_work_t
|
|
>::value
|
|
>::type
|
|
> : asio::detail::thread_pool_bits
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::execution::outstanding_work_t result_type;
|
|
|
|
static constexpr result_type value() noexcept
|
|
{
|
|
return (Bits & outstanding_work_tracked)
|
|
? execution::outstanding_work_t(execution::outstanding_work.tracked)
|
|
: execution::outstanding_work_t(execution::outstanding_work.untracked);
|
|
}
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Property>
|
|
struct query_static_constexpr_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Property,
|
|
typename asio::enable_if<
|
|
asio::is_convertible<
|
|
Property,
|
|
asio::execution::mapping_t
|
|
>::value
|
|
>::type
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::execution::mapping_t::thread_t result_type;
|
|
|
|
static constexpr result_type value() noexcept
|
|
{
|
|
return result_type();
|
|
}
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Property>
|
|
struct query_static_constexpr_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Property,
|
|
typename asio::enable_if<
|
|
asio::is_convertible<
|
|
Property,
|
|
asio::execution::inline_exception_handling_t
|
|
>::value
|
|
>::type
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::execution::inline_exception_handling_t::terminate_t
|
|
result_type;
|
|
|
|
static constexpr result_type value() noexcept
|
|
{
|
|
return result_type();
|
|
}
|
|
};
|
|
|
|
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_STATIC_CONSTEXPR_MEMBER_TRAIT)
|
|
|
|
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Property>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Property,
|
|
typename asio::enable_if<
|
|
asio::is_convertible<
|
|
Property,
|
|
asio::execution::blocking_t
|
|
>::value
|
|
>::type
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::execution::blocking_t result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits, typename Property>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
Property,
|
|
typename asio::enable_if<
|
|
asio::is_convertible<
|
|
Property,
|
|
asio::execution::relationship_t
|
|
>::value
|
|
>::type
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::execution::relationship_t result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::occupancy_t
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef std::size_t result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::context_t
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef asio::thread_pool& result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::allocator_t<void>
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef Allocator result_type;
|
|
};
|
|
|
|
template <typename Allocator, unsigned int Bits, typename OtherAllocator>
|
|
struct query_member<
|
|
asio::thread_pool::basic_executor_type<Allocator, Bits>,
|
|
asio::execution::allocator_t<OtherAllocator>
|
|
>
|
|
{
|
|
static constexpr bool is_valid = true;
|
|
static constexpr bool is_noexcept = true;
|
|
typedef Allocator result_type;
|
|
};
|
|
|
|
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
|
|
|
|
} // namespace traits
|
|
|
|
namespace execution {
|
|
|
|
template <>
|
|
struct is_executor<thread_pool> : false_type
|
|
{
|
|
};
|
|
|
|
} // namespace execution
|
|
|
|
#endif // !defined(GENERATING_DOCUMENTATION)
|
|
|
|
ASIO_INLINE_NAMESPACE_END
|
|
} // namespace asio
|
|
|
|
#include "asio/detail/pop_options.hpp"
|
|
|
|
#include "asio/impl/thread_pool.hpp"
|
|
#if defined(ASIO_HEADER_ONLY)
|
|
# include "asio/impl/thread_pool.ipp"
|
|
#endif // defined(ASIO_HEADER_ONLY)
|
|
|
|
#endif // ASIO_THREAD_POOL_HPP
|