1 | // |
2 | // Activity.h |
3 | // |
4 | // Library: Foundation |
5 | // Package: Threading |
6 | // Module: ActiveObjects |
7 | // |
8 | // Definition of the Activity template class. |
9 | // |
10 | // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. |
11 | // and Contributors. |
12 | // |
13 | // SPDX-License-Identifier: BSL-1.0 |
14 | // |
15 | |
16 | |
17 | #ifndef Foundation_Activity_INCLUDED |
18 | #define Foundation_Activity_INCLUDED |
19 | |
20 | |
21 | #include "Poco/Foundation.h" |
22 | #include "Poco/RunnableAdapter.h" |
23 | #include "Poco/ThreadPool.h" |
24 | #include "Poco/Event.h" |
25 | #include "Poco/Mutex.h" |
26 | |
27 | |
28 | namespace Poco { |
29 | |
30 | |
31 | template <class C> |
32 | class Activity: public Runnable |
33 | /// This template class helps to implement active objects. |
34 | /// An active object uses threads to decouple method |
35 | /// execution from method invocation, or to perform tasks |
36 | /// autonomously, without intervention of a caller. |
37 | /// |
38 | /// An activity is a (typically longer running) method |
39 | /// that executes within its own task. Activities can |
40 | /// be started automatically (upon object construction) |
41 | /// or manually at a later time. Activities can also |
42 | /// be stopped at any time. However, to make stopping |
43 | /// an activity work, the method implementing the |
44 | /// activity has to check periodically whether it |
45 | /// has been requested to stop, and if so, return. |
46 | /// Activities are stopped before the object they belong to is |
47 | /// destroyed. Methods implementing activities cannot have arguments |
48 | /// or return values. |
49 | /// |
50 | /// Activity objects are used as follows: |
51 | /// |
52 | /// class ActiveObject |
53 | /// { |
54 | /// public: |
55 | /// ActiveObject(): |
56 | /// _activity(this, &ActiveObject::runActivity) |
57 | /// { |
58 | /// ... |
59 | /// } |
60 | /// |
61 | /// ... |
62 | /// |
63 | /// protected: |
64 | /// void runActivity() |
65 | /// { |
66 | /// while (!_activity.isStopped()) |
67 | /// { |
68 | /// ... |
69 | /// } |
70 | /// } |
71 | /// |
72 | /// private: |
73 | /// Activity<ActiveObject> _activity; |
74 | /// }; |
75 | { |
76 | public: |
77 | typedef RunnableAdapter<C> RunnableAdapterType; |
78 | typedef typename RunnableAdapterType::Callback Callback; |
79 | |
80 | Activity(C* pOwner, Callback method): |
81 | _pOwner(pOwner), |
82 | _runnable(*pOwner, method), |
83 | _stopped(true), |
84 | _running(false), |
85 | _done(Event::EVENT_MANUALRESET) |
86 | /// Creates the activity. Call start() to |
87 | /// start it. |
88 | { |
89 | poco_check_ptr (pOwner); |
90 | } |
91 | |
92 | ~Activity() |
93 | /// Stops and destroys the activity. |
94 | { |
95 | try |
96 | { |
97 | stop(); |
98 | wait(); |
99 | } |
100 | catch (...) |
101 | { |
102 | poco_unexpected(); |
103 | } |
104 | } |
105 | |
106 | void start() |
107 | /// Starts the activity by acquiring a |
108 | /// thread for it from the default thread pool. |
109 | { |
110 | start(ThreadPool::defaultPool()); |
111 | } |
112 | |
113 | void start(ThreadPool& pool) |
114 | { |
115 | FastMutex::ScopedLock lock(_mutex); |
116 | if (!_running) |
117 | { |
118 | _done.reset(); |
119 | _stopped = false; |
120 | _running = true; |
121 | try |
122 | { |
123 | pool.start(*this); |
124 | } |
125 | catch (...) |
126 | { |
127 | _running = false; |
128 | throw; |
129 | } |
130 | } |
131 | } |
132 | |
133 | void stop() |
134 | /// Requests to stop the activity. |
135 | { |
136 | FastMutex::ScopedLock lock(_mutex); |
137 | _stopped = true; |
138 | } |
139 | |
140 | void wait() |
141 | /// Waits for the activity to complete. |
142 | { |
143 | if (_running) |
144 | { |
145 | _done.wait(); |
146 | } |
147 | } |
148 | |
149 | void wait(long milliseconds) |
150 | /// Waits the given interval for the activity to complete. |
151 | /// An TimeoutException is thrown if the activity does not |
152 | /// complete within the given interval. |
153 | { |
154 | if (_running) |
155 | { |
156 | _done.wait(milliseconds); |
157 | } |
158 | } |
159 | |
160 | bool isStopped() const |
161 | /// Returns true if the activity has been requested to stop. |
162 | { |
163 | return _stopped; |
164 | } |
165 | |
166 | bool isRunning() const |
167 | /// Returns true if the activity is running. |
168 | { |
169 | return _running; |
170 | } |
171 | |
172 | protected: |
173 | void run() |
174 | { |
175 | try |
176 | { |
177 | _runnable.run(); |
178 | } |
179 | catch (...) |
180 | { |
181 | _running = false; |
182 | _done.set(); |
183 | throw; |
184 | } |
185 | _running = false; |
186 | _done.set(); |
187 | } |
188 | |
189 | private: |
190 | Activity(); |
191 | Activity(const Activity&); |
192 | Activity& operator = (const Activity&); |
193 | |
194 | C* _pOwner; |
195 | RunnableAdapterType _runnable; |
196 | std::atomic<bool> _stopped; |
197 | std::atomic<bool> _running; |
198 | Event _done; |
199 | FastMutex _mutex; |
200 | }; |
201 | |
202 | |
203 | } // namespace Poco |
204 | |
205 | |
206 | #endif // Foundation_Activity_INCLUDED |
207 | |