SObjectizer  5.8
Loading...
Searching...
No Matches
work_thread_template.hpp
Go to the documentation of this file.
1/*
2 * SObjectizer-5
3 */
4
5/*!
6 * \file
7 * \brief A reusable implementation of work_thread_template that can be used by
8 * various thread-pool dispatchers.
9 *
10 * \since v.5.8.0
11 */
12
13#pragma once
14
15#include <so_5/stats/impl/activity_tracking.hpp>
16
17#include <so_5/disp/abstract_work_thread.hpp>
18
19#include <so_5/disp/thread_pool/impl/common_implementation.hpp>
20
21#include <so_5/impl/thread_join_stuff.hpp>
22
23namespace so_5
24{
25
26namespace disp
27{
28
29namespace thread_pool
30{
31
32namespace impl
33{
34
36{
37
38/*!
39 * \brief Part of %common_data_t that depends on a template parameter.
40 *
41 * Intended to be used as a mixin for common_data_t type.
42 */
43template< typename Disp_Queue >
45 {
46 //! Dispatcher's queue.
47 Disp_Queue * m_disp_queue;
48
53 };
54
55/*!
56 * \brief Part of %common_data_t that doesn't depend on a template parameter.
57 *
58 * Intended to be used as a mixin for common_data_t type.
59 */
61 {
62 //! ID of thread.
63 /*!
64 * Receives actual value inside body().
65 */
67
68 //! Actual thread.
70
71 //! Waiting object for long wait.
73
75 work_thread_holder_t thread_holder,
76 so_5::disp::mpmc_queue_traits::condition_unique_ptr_t condition )
79 {}
80 };
81
82/*!
83 * \brief Main data for work_thread.
84 *
85 * \since v.5.5.18
86 */
87template< typename Disp_Queue >
102
103/*!
104 * \brief Part of implementation of work thread without activity tracing.
105 *
106 * \since v.5.5.18
107 */
108template< typename Disp_Queue >
109class no_activity_tracking_impl_t : protected common_data_t< Disp_Queue >
110 {
111 public :
112 /*!
113 * \brief Mandatory alias for Disp_Queue.
114 *
115 * This alias is then be used by the work_thread_template_t template.
116 */
117 using disp_queue_t = Disp_Queue;
118
119 //! Initializing constructor.
125
126 template< typename L >
127 void
128 take_activity_stats( L ) { /* Nothing to do */ }
129
130 protected :
131 void
133
134 void
136
137 void
139
140 void
142 };
143
144/*!
145 * \brief Part of implementation of work thread with activity tracing.
146 *
147 * \since v.5.5.18
148 */
149template< typename Disp_Queue >
150class with_activity_tracking_impl_t : protected common_data_t< Disp_Queue >
151 {
152 using activity_tracking_traits = so_5::stats::activity_tracking_stuff::traits;
153
154 public :
155 /*!
156 * \brief Mandatory alias for Disp_Queue.
157 *
158 * This alias is then be used by the work_thread_template_t template.
159 */
160 using disp_queue_t = Disp_Queue;
161
162 //! Initializing constructor.
168
169 template< typename L >
170 void
180
181 protected :
182 //! Lock for activity statistics.
183 activity_tracking_traits::lock_t m_stats_lock;
184
185 //! A collector for work activity.
189
190 //! A collector for waiting stats.
194
195 void
200
201 void
206
207 void
212
213 void
218 };
219
220//
221// work_thread_template_t
222//
223/*!
224 * \brief Implementation of work_thread in form of template class.
225 *
226 * \since v.5.5.18
227 */
228template< typename Impl >
229class work_thread_template_t final : public Impl
230 {
231 public :
232 using disp_queue_t = typename Impl::disp_queue_t;
233
234 private:
235 using agent_queue_t = typename disp_queue_t::item_t;
236
237 public:
238 //! Initializing constructor.
240 outliving_reference_t< disp_queue_t > queue,
241 work_thread_holder_t thread_holder )
242 : Impl( queue, std::move(thread_holder) )
243 {}
244
245 void
247 {
248 so_5::impl::ensure_join_from_different_thread( this->m_thread_id );
249 this->m_thread_holder.unchecked_get().join();
250 }
251
252 //! Launch work thread.
253 void
255 {
256 this->m_thread_holder.unchecked_get().start( [this]() { body(); } );
257 }
258
259 /*!
260 * \brief Get ID of work thread.
261 *
262 * \note This method returns correct value only after start
263 * of the thread.
264 *
265 * \since v.5.5.18
266 */
268 thread_id() const
269 {
270 return this->m_thread_id;
271 }
272
273 private :
274 //! Thread body method.
275 void
277 {
278 this->m_thread_id = so_5::query_current_thread_id();
279
280 agent_queue_t * agent_queue;
281 while( nullptr != (agent_queue = this->pop_agent_queue()) )
282 {
283 this->do_queue_processing( agent_queue );
284 }
285 }
286
287 /*!
288 * \brief An attempt of extraction of non-empty agent queue.
289 *
290 * \note This is noexcept method because its logic can't survive
291 * an exception from m_disp_queue->pop.
292 *
293 * \since v.5.5.18
294 */
295 [[nodiscard]]
296 agent_queue_t *
298 {
299 agent_queue_t * result = nullptr;
300
301 this->wait_started();
302
303 result = this->m_disp_queue->pop( *(this->m_condition) );
304
305 this->wait_finished();
306
307 return result;
308 }
309
310 /*!
311 * \brief Starts processing of demands from the queue specified.
312 *
313 * Starts from \a current_queue. Processes up to enabled number
314 * of events from that queue. Then if the queue is not empty
315 * tries to find another non-empty queue. If there is no such queue
316 * then continue processing of \a current_queue.
317 *
318 * \since v.5.5.15.1
319 */
320 void
321 do_queue_processing( agent_queue_t * current_queue )
322 {
323 do
324 {
325 const auto e = this->process_queue( *current_queue );
326
327 if( agent_queue_t::emptyness_t::not_empty == e )
328 {
329 // We can continue processing of that queue if
330 // there is no more non-empty queues waiting.
331 current_queue =
332 this->m_disp_queue->try_switch_to_another(
333 current_queue );
334 }
335 else
336 // Handling of the current queue should be stopped.
337 current_queue = nullptr;
338 }
339 while( current_queue != nullptr );
340 }
341
342
343 //! Processing of demands from agent queue.
344 [[nodiscard]]
345 typename agent_queue_t::emptyness_t
346 process_queue( agent_queue_t & queue )
347 {
348 std::size_t demands_processed = 0;
349 typename agent_queue_t::pop_result_t pop_result;
350
351 do
352 {
353 auto & d = queue.front();
354
355 this->work_started();
356
357 d.call_handler( this->m_thread_id );
358
359 this->work_finished();
360
361 ++demands_processed;
362 pop_result = queue.pop( demands_processed );
363 }
364 while( agent_queue_t::processing_continuation_t::enabled ==
365 pop_result.m_continuation );
366
367 return pop_result.m_emptyness;
368 }
369 };
370
371} /* namespace work_thread_details */
372
373//
374// work_thread_no_activity_tracking_t
375//
376/*!
377 * \brief Type of work thread without activity tracking.
378 *
379 * \since v.5.5.18
380 */
381template< typename Disp_Queue >
382using work_thread_no_activity_tracking_t =
383 work_thread_details::work_thread_template_t<
385
386//
387// work_thread_with_activity_tracking_t
388//
389/*!
390 * \brief Type of work thread without activity tracking.
391 *
392 * \since v.5.5.18
393 */
394template< typename Disp_Queue >
395using work_thread_with_activity_tracking_t =
396 work_thread_details::work_thread_template_t<
398
399} /* namespace impl */
400
401} /* namespace thread_pool */
402
403} /* namespace disp */
404
405} /* namespace so_5 */
A base class for agents.
Definition agent.hpp:673
The base class for the object with a reference counting.
Container for storing parameters for MPMC queue.
Parameters for binding agents to nef_thread_pool dispatcher.
bind_params_t & max_demands_at_once(std::size_t v)
Set maximum count of demands to be processed at once.
std::size_t m_max_demands_at_once
Maximum count of demands to be processed at once.
std::size_t query_max_demands_at_once() const
Get maximum count of demands to do processed at once.
Alias for namespace with traits of event queue.
const queue_traits::queue_params_t & queue_params() const
Getter for queue parameters.
std::size_t m_thread_count
Count of working threads.
disp_params_t & tune_queue_params(L tunner)
Tuner for queue parameters.
disp_params_t & set_queue_params(queue_traits::queue_params_t p)
Setter for queue parameters.
queue_traits::queue_params_t m_queue_params
Queue parameters.
disp_params_t & thread_count(std::size_t count)
Setter for thread count.
friend void swap(disp_params_t &a, disp_params_t &b) noexcept
std::size_t thread_count() const
Getter for thread count.
disp_params_t()=default
Default constructor.
A handle for nef_thread_pool dispatcher.
impl::basic_dispatcher_iface_shptr_t m_dispatcher
A reference to actual implementation of a dispatcher.
bool empty() const noexcept
Is this handle empty?
disp_binder_shptr_t binder(bind_params_t params) const
Get a binder for that dispatcher.
dispatcher_handle_t(impl::basic_dispatcher_iface_shptr_t dispatcher) noexcept
void bind(agent_t &agent) noexcept override
Bind agent to dispatcher.
actual_binder_t(actual_dispatcher_iface_shptr_t disp, bind_params_t params) noexcept
const bind_params_t m_params
Binding parameters.
actual_dispatcher_iface_shptr_t m_disp
Dispatcher to be used.
void preallocate_resources(agent_t &agent) override
Allocate resources in dispatcher for new agent.
void undo_preallocation(agent_t &agent) noexcept override
Undo resources allocation.
void unbind(agent_t &agent) noexcept override
Unbind agent from dispatcher.
An actual interface of nef-thread-pool dispatcher.
virtual event_queue_t * query_resources_for_agent(agent_t &agent) noexcept=0
Get resources allocated for an agent.
virtual void undo_preallocation_for_agent(agent_t &agent) noexcept=0
Undo preallocation of resources for a new agent.
virtual void unbind_agent(agent_t &agent) noexcept=0
Unbind agent from the dispatcher.
virtual void preallocate_resources_for_agent(agent_t &agent, const bind_params_t &params)=0
Preallocate all necessary resources for a new agent.
void undo_preallocation_for_agent(agent_t &agent) noexcept override
Undo preallocation of resources for a new agent.
event_queue_t * query_resources_for_agent(agent_t &agent) noexcept override
Get resources allocated for an agent.
void preallocate_resources_for_agent(agent_t &agent, const bind_params_t &params) override
Preallocate all necessary resources for a new agent.
actual_dispatcher_implementation_t(outliving_reference_t< environment_t > env, const std::string_view name_base, disp_params_t params)
dispatcher_template_t< Work_Thread > m_impl
Real dispatcher.
void unbind_agent(agent_t &agent) noexcept override
Unbind agent from the dispatcher.
void schedule_on_disp_queue() noexcept override
Perform scheduling of processing of this event queue.
dispatcher_queue_t & m_disp_queue
Dispatcher queue with that the agent queue has to be used.
agent_queue_with_preallocated_finish_demand_t * intrusive_queue_giveout_next() noexcept
Give away a pointer to the next agent_queue.
std::unique_ptr< base_type_t::demand_t > m_finish_demand
A preallocated demand for evt_finish.
agent_queue_with_preallocated_finish_demand_t * m_intrusive_queue_next
The next item in intrusive queue of agent_queues.
agent_queue_with_preallocated_finish_demand_t(outliving_reference_t< dispatcher_queue_t > disp_queue, const bind_params_t &params)
Initializing constructor.
void intrusive_queue_set_next(agent_queue_with_preallocated_finish_demand_t *next) noexcept
Set a pointer to the next agent_queue.
The very basic interface of thread_pool dispatcher.
virtual disp_binder_shptr_t binder(bind_params_t params)=0
static dispatcher_handle_t make(actual_dispatcher_iface_shptr_t disp) noexcept
Multi-producer/Multi-consumer queue of pointers to event queues.
Mixin that holds optional work thread factory.
std::vector< std::unique_ptr< Work_Thread > > m_threads
Pool of work threads.
void wait_for_emptyness() noexcept
Wait while queue becomes empty.
Part of implementation of work thread without activity tracing.
no_activity_tracking_impl_t(outliving_reference_t< Disp_Queue > queue, work_thread_holder_t thread_holder)
Initializing constructor.
with_activity_tracking_impl_t(outliving_reference_t< Disp_Queue > queue, work_thread_holder_t thread_holder)
Initializing constructor.
activity_tracking_traits::lock_t m_stats_lock
Lock for activity statistics.
so_5::stats::activity_tracking_stuff::stats_collector_t< so_5::stats::activity_tracking_stuff::external_lock<> > m_waiting_stats_collector
A collector for waiting stats.
so_5::stats::activity_tracking_stuff::stats_collector_t< so_5::stats::activity_tracking_stuff::external_lock<> > m_work_activity_collector
A collector for work activity.
agent_queue_t * pop_agent_queue() noexcept
An attempt of extraction of non-empty agent queue.
work_thread_template_t(outliving_reference_t< disp_queue_t > queue, work_thread_holder_t thread_holder)
Initializing constructor.
agent_queue_t::emptyness_t process_queue(agent_queue_t &queue)
Processing of demands from agent queue.
void do_queue_processing(agent_queue_t *current_queue)
Starts processing of demands from the queue specified.
so_5::current_thread_id_t thread_id() const
Get ID of work thread.
An analog of unique_ptr for abstract_work_thread.
Interface for dispatcher binders.
SObjectizer Environment.
An interface of event queue for agent.
Template class for smart reference wrapper on the atomic_refcounted_t.
Helper class for indication of long-lived reference via its type.
Definition outliving.hpp:98
#define SO_5_FUNC
Definition declspec.hpp:48
Various stuff related to MPMC event queue implementation and tuning.
void adjust_thread_count(disp_params_t &params)
Sets the thread count to default value if used do not specify actual thread count.
SO_5_FUNC dispatcher_handle_t make_dispatcher(environment_t &env, const std::string_view data_sources_name_base, disp_params_t params)
Create an instance nef_thread_pool dispatcher.
dispatcher_handle_t make_dispatcher(environment_t &env, const std::string_view data_sources_name_base, std::size_t thread_count)
Create an instance of nef_thread_pool dispatcher.
dispatcher_handle_t make_dispatcher(environment_t &env, std::size_t thread_count)
Create an instance of nef_thread_pool dispatcher.
dispatcher_handle_t make_dispatcher(environment_t &env)
Create an instance of nef_thread_pool dispatcher with the default count of working threads.
Reusable components for dispatchers.
Reusable implementation of some thread pool dispatcher functionality which can be used in other threa...
Internal implementation details of thread pool dispatcher.
Thread pool dispatcher.
Event dispatchers.
All stuff related to run-time monitoring and statistics.
Private part of message limit implementation.
Definition agent.cpp:33
Adaptation of common implementation of thread-pool-like dispatcher to the specific of this thread-poo...
static bool is_individual_fifo(const bind_params_t &) noexcept
static constexpr std::string_view dispatcher_type_name() noexcept
static void wait_for_queue_emptyness(agent_queue_with_preallocated_finish_demand_t &queue) noexcept
common_data_t(outliving_reference_t< Disp_Queue > queue, work_thread_holder_t thread_holder)
Part of common_data_t that doesn't depend on a template parameter.
so_5::disp::mpmc_queue_traits::condition_unique_ptr_t m_condition
Waiting object for long wait.
common_data_template_independent_t(work_thread_holder_t thread_holder, so_5::disp::mpmc_queue_traits::condition_unique_ptr_t condition)
A description of event execution demand.
Various traits of activity tracking implementation.