-
Notifications
You must be signed in to change notification settings - Fork 23
/
Copy pathAOThread.h
147 lines (114 loc) · 3.8 KB
/
AOThread.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
/*
* AOThread.h
*
* Created on: Dec 30, 2020
* Author: <a href="mailto:damirlj@yahoo.com">Damir Ljubic</a>
*/
#ifndef AOT_AOTHREAD_H_
#define AOT_AOTHREAD_H_
#include <memory>
#include <string>
#include <iostream>
#include "JobQueue.h"
#include "Commons.h"
#include "ThreadWrapper.h"
namespace utils::aot
{
/**
* AOT - Active Object Thread design pattern.
*
* Provides the thread context for executing asynchronous tasks.
* The interaction with the client code is through restrictive interface which exposes single
* method for tasks to be serialized - stored into the jobs queue.
* Thread drains the queue providing the background context in which tasks will be executed
* sequentially, one-by-one.
*
* @tparam R Return value type of task
*
*/
template <typename R = void>
class AOThread final
{
public:
using task_queue_t = JobQueue<R>;
AOThread(std::string name
, utils::thread::ThreadWrapper::schedule_t policy
, utils::thread::ThreadWrapper::priority_t priority):
m_pJobQueue (std::make_unique<task_queue_t>()),
m_pJobThread(utils::thread::make_thread_ptr(&AOThread::threadFunc, this))
{
start(name, policy, priority);
}
~AOThread()//user-defined c-tor: prevents generating default (memberwise) move-operations
{
stop();
}
// Copy-operations explicit forbidden
AOThread(const AOThread&) = delete;
AOThread& operator = (const AOThread&) = delete;
/**
* Enqueue the task
*
* @note If the job should have an additional arguments,
* use std::bind - to bind the task with the arguments.
*
* @param job The task to be enqueued
* @return The future, for waiting on result, if any
*/
auto enqueue(utils::aot::job_t<R>&& job) noexcept
{
return m_pJobQueue->enqueue(std::move(job));//thread-safe task queue
}
private:
void start(std::string name
, utils::thread::ThreadWrapper::schedule_t policy
, int priority) noexcept
{
if (m_pJobThread)
{
(void)m_pJobThread->setName(name);
(void)m_pJobThread->setPriority(policy, priority);
}
}
void stop()
{
m_pJobQueue->stop();//stop dequeuing: signal thread exit
if (m_pJobThread)
{
m_pJobThread.reset(nullptr);//wait on jobs thread to join
}
}
/**
* Serialized all tasks to be executed sequentially,
* within the single background thread
*/
void threadFunc() noexcept;
private:
std::unique_ptr<task_queue_t> m_pJobQueue = nullptr;
utils::thread::thread_ptr_t m_pJobThread = nullptr;
};
template <typename R>
void AOThread<R>::threadFunc() noexcept
{
using namespace std;
for(;;)
{
// Suspend thread, until the queue is empty or exit is not signaled
auto job = m_pJobQueue->dequeue();
if (!job) //exit signaled
{
break;
}
try
{
(*job)();
}
catch(const std::bad_function_call& e)
{
//todo: add logging policy
break;
}
}//for(;;)
}
} /* namespace utils::aot */
#endif /* AOT_AOTHREAD_H_ */