c++-gtk-utils: notifier.h Source File

c++-gtk-utils

- Main Page
- Related Pages
- Modules
- Namespaces
- Classes
- Files

- File List
- File Members

notifier.h
Go to the documentation of this file.
1 /* Copyright (C) 2005 to 2014 Chris Vine
2
3 The library comprised in this file or of which this file is part is
4 distributed by Chris Vine under the GNU Lesser General Public
5 License as follows:
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Lesser General Public License
9 as published by the Free Software Foundation; either version 2.1 of
10 the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License, version 2.1, for more details.
16
17 You should have received a copy of the GNU Lesser General Public
18 License, version 2.1, along with this library (see the file LGPL.TXT
19 which came with this source code package in the c++-gtk-utils
20 sub-directory); if not, write to the Free Software Foundation, Inc.,
21 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22
23 */
24
25 #ifndef CGU_NOTIFIER_H
26 #define CGU_NOTIFIER_H
27
28 /**
29 * @file notifier.h
30 * @brief This file provides a Notifier class to provide thread-safe
31 * signalling between a worker thread and the main program thread.
32 *
33 * For further details read this: Notifier.
34 */
35
36 #include <unordered_set>
37 #include <type_traits> // for std::remove_reference, std::enable_if and std::is_convertible
38
39 #include <pthread.h>
40
41 #include <c++-gtk-utils/pipes.h>
42 #include <c++-gtk-utils/io_watch.h>
43 #include <c++-gtk-utils/emitter.h>
44 #include <c++-gtk-utils/cgu_config.h>
45
46 namespace Cgu {
47
48 /**
49 * @class Notifier notifier.h c++-gtk-utils/notifier.h
50 * @brief Provides thread-safe signalling between a worker thread and
51 * the main program thread.
52 * @sa Callback namespace Callback::post()
53 * @sa EmitterArg SafeEmitterArg Releaser
54 *
55 * The Notifier class provides thread-safe signalling between two
56 * threads. It does this through a pipe, to which an GSource (iowatch)
57 * object is attached to connect it to the glib program event loop.
58 * Callable objects (such as lambda expressions or the return value of
59 * std::bind) or Callback::SafeFunctor objects may be connected to the
60 * Notifier (referred to be below as "connected callables"), which are
61 * called in the receiving thread via the program event loop when
62 * operator()() (or emit()) is called on the Notifier object by the
63 * signalling thread. It therefore behaves like a SafeEmitter object,
64 * except that connected callables execute in the glib program event
65 * loop thread rather than in the thread which calls
66 * operator()()/emit().
67 *
68 * It is an alternative to the Callback::post() function in
69 * callback.h, and the documentation on callback.h contains a
70 * description of relevant trade-offs between the two.
71 *
72 * If the signalling thread is the same thread as that in which the
73 * connected callables will execute (which is the thread in which the
74 * default glib program event loop executes), executing them via the
75 * pipe would risk a deadlock - if the pipe fills up, the thread would
76 * block on write and never be able to read from the pipe to empty it.
77 * Accordingly, if the Notifier object is invoked by the same thread
78 * as that in which the connected callables will execute, this is
79 * detected and they will be invoked directly, rather than via the
80 * pipe. Therefore, actions so invoked may be out of order with those
81 * invoked by the other threads.
82 *
83 * If a Releaser object is passed as the second argument of
84 * Notifier::connect(), then the connected callable concerned will
85 * automatically be disconnected if the object which has the Releaser
86 * object as a member is destroyed.
87 *
88 * The main use of Notifier objects is for a worker thread to signal
89 * an event to the main thread in which GTK is executing, which
90 * implies that GTK should also be executing in the default glib
91 * program event loop (GMainContext) (as will almost always be the
92 * case), which is the one with which the program first starts.
93 * Before a Notifier object is first used, it is a requirement that
94 * Notifier::init() (a static member function) be called in the thread
95 * in which the default glib event loop executes, and any connected
96 * callables will execute in that thread. Notifier::init() only needs
97 * to be called once at program start-up - it doesn't need to be
98 * called separately for each Notifier object, and can be called
99 * before any Notifier objects have been constructed. If it has not
100 * been called before the construction of the first Notifier object
101 * has taken place, it will occur automatically on that first
102 * construction. That means that if the first Notifier object is not
103 * constructed in the main (event loop) thread of the program, then
104 * Notifier::init() must be called explicitly before that first object
105 * is constructed. In addition, if glib < 2.32 is installed, before
106 * Notifier::init() is called (or the first Notifier object created)
107 * g_thread_init(0) should have been called: as a result a Notifier
108 * object cannot be a global (non-local) static object with glib <
109 * 2.32 (glib >= 2.32 does not require g_thread_init() to be called to
110 * be thread safe). Note also that global static Notifier objects are
111 * not safe prior to version 2.0.15, even with glib >= 2.32.
112 *
113 * It is a good idea that Notifier::init() should have been called (or
114 * the first Notifier object constructed) before the main program
115 * thread creates any new threads. Then the state of initialisation
116 * effected by Notifier::init() will automatically be visible between
117 * threads.
118 *
119 * When executing connected callables, a check is made for a case
120 * where between the signalling thread invoking a Notifier object and
121 * the main program event loop executing the callables, the Notifier
122 * object ceases to exist. However there can still be a race
123 * condition if the lifetime of the Notifier object is determined
124 * outside the thread of execution of the main program event loop and
125 * a Notifier object is destroyed by that other thread between the
126 * time the check is made and the callables executed. Normally
127 * Notifier objects are constructed and destroyed in the main program
128 * thread, but where that is not the case the user will need to take
129 * this into account and if need be provide appropriate
130 * synchronisation to secure the lifetime of the Notifier object until
131 * after the callables have been executed. Likewise, a Releaser
132 * object cannot offer protection if the remote object whose
133 * non-static method is represented or called into by a connected
134 * callable is destroyed by another thread while the main program loop
135 * is in the middle of executing the callable. When the main loop
136 * begins executing a callable, the remote object must either wholly
137 * exist (in which case the callable will be invoked) or have been
138 * destroyed (in which case the callable will be ignored), and not be
139 * in some transient half-state governed by another thread.
140 *
141 * Apart from that, the Notifier object is thread-safe and any of its
142 * methods may be invoked in any thread. (It is as thread-safe as a
143 * SafeEmitter object, as described in emitter.h, which contains
144 * further details on thread safety.)
145 *
146 * To pass variable data to a connected callable, the AsyncQueue class
147 * can be employed.
148 *
149 * @b Usage
150 *
151 * This is an example:
152 *
153 * @code
154 * using namespace Cgu;
155 *
156 * // assume a Notifier object 'notifier' has been constructed at some other point in the program
157 * notifier.connect([] () {std::cout << "Hello world\n";});
158 * notifier(); // callable executes in glib main loop
159 * @endcode
160 *
161 * Callback::SafeFunctor objects may be connected to a notifier, and
162 * the connect() method may be directly initialized with the result of
163 * Callback::make(), Callback::make_ref() or Callback::lambda() and
164 * implicit conversion will take place. Here is an example using
165 * Callback::make_ref(), with a class object my_obj of type MyClass,
166 * with a method void MyClass::my_method(int, const Something&):
167 *
168 * @code
169 * using namespace Cgu;
170 *
171 * int arg1 = 1;
172 * Something arg2;
173 * notifier.connect(Callback::make_ref(my_obj, &MyClass::my_method, arg1, arg2));
174 * notifier(); // callable executes in glib main loop
175 * @endcode
176 *
177 */
178
179 /*
180 For a program with two GMainContext program event loops (not a usual
181 case), it would be possible for a Notifier-like object to be
182 initialised in the non-default GMainContext thread, and execute in
183 that thread, by passing that other GMainContext object as the last
184 argument when calling start_iowatch() in Notifier::Notifier().
185 However, to conserve file descriptors all Notifier objects share a
186 common pipe and iowatch event watch, which implies that all Notifier
187 objects would also need to execute in that other thread. To get
188 around this it would be possible either to templatize Notifier with
189 tag types for different GMainContexts (so that there would be a
190 different static pipe/iowatch object for each GMainContext), or to
191 have thread-local storage for each of the static objects in the
192 Notifier class, but an easier solution for one-off cases would be to
193 have a version of Notifier which does not use static (shared)
194 PipeFifo and iowatch objects, at the expense of greater use of file
195 descriptor resources.
196
197 Such a special Notifier object could also be used to signal from a
198 Unix (asynchronous) signal/interrupt handler, but in that case the
199 write file descriptor of the pipe should be set non-blocking to
200 prevent the very unlikely but theoretically possible case (in a
201 program executing in a system under extreme load) of the pipe
202 filling up before being emptied by the Notifier::read_pipe_cb()
203 callback function executing in the main program and so blocking in
204 the handler, thus deadlocking the program.
205 */
206
207
208 namespace Thread {
209 class Mutex;
210 }
211
212 class Notifier;
213
214 class Notifier {
215
216 static bool initialised;
217 static pthread_t thread_id;
218 // pointers can be keys of associative containers: "For templates
219 // greater, less, greater_equal, and less_equal, the specializations
220 // for any pointer type yield a total order, even if the built-in
221 // operators <, >, <=, >= do not." (para 20.3.3/8).
222 static std::unordered_set<Notifier*>* object_set_p;
223 static PipeFifo* pipe_p;
224 static Thread::Mutex* set_mutex_p;
225 static Thread::Mutex* write_mutex_p;
226 static void read_pipe_cb(bool&);
227
228 SafeEmitter emitter;
229 public:
230 /**
231 * This class cannot be copied. The copy constructor is deleted.
232 */
233 Notifier(const Notifier&) = delete;
234
235 /**
236 * This class cannot be copied. The assignment operator is deleted.
237 */
238 Notifier& operator=(const Notifier&) = delete;
239
240 /**
241 * A utility which tells the caller whether it is in the thread in
242 * which the callback will execute (the main program thread). It will
243 * not throw. It is thread safe.
244 * @return true if the caller is in the thread in which the callback
245 * will execute, otherwise false.
246 */
247 // don't make this a static member function - it can then only be called
248 // by object notation after a Notifier object has first been constructed,
249 // which means Notifier::init() must have been called
250 bool in_main_thread() noexcept {return pthread_equal(thread_id, pthread_self());}
251
252 /**
253 * This will cause the connected functors to be executed in the main
254 * program thread. It is thread safe (but see the comments in the
255 * introductory remarks above about race conditions where the lifetime
256 * of a Notifier object is determined by a thread other than the main
257 * program thread, and about protection by a Releaser object where a
258 * connected remote object is destroyed in mid-emission by another
259 * thread).
260 * @exception std::bad_alloc The method might throw std::bad_alloc if
261 * memory is exhausted and the system throws in that case, and this
262 * method is called in the thread in which the functors will execute
263 * (the main program thread). In addition, it will throw if the
264 * function or class methods represented by the functors throw (or if
265 * the assignment operator of a bound argument throws) and the call is
266 * made in that thread. If called in a different thread it will not
267 * throw (in that case, an exception thrown by a connected functor
268 * will be consumed to protect the glib main loop and the iowatch
269 * dispatcher will issue a g_critical() warning).
270 */
271 void emit();
272
273 /**
274 * This will cause the connected functors to be executed in the main
275 * program thread. It is thread safe (but see the comments in the
276 * introductory remarks above about race conditions where the lifetime
277 * of a Notifier object is determined by a thread other than the main
278 * program thread, and about protection by a Releaser object where a
279 * connected remote object is destroyed in mid-emission by another
280 * thread).
281 * @exception std::bad_alloc The method might throw std::bad_alloc if
282 * memory is exhausted and the system throws in that case, and this
283 * method is called in the thread in which the functors will execute
284 * (the main program thread). In addition, it will throw if the
285 * function or class methods represented by the functors throw (or if
286 * the assignment operator of a bound argument throws) and the call is
287 * made in that thread. If called in a different thread it will not
288 * throw (in that case, an exception thrown by a connected functor
289 * will be consumed to protect the glib main loop and the iowatch
290 * dispatcher will issue a g_critical() warning).
291 */
292 void operator()() {emit();}
293
294 /**
295 * Connects a functor. It is thread safe.
296 * @param f The functor to connect.
297 * @return The functor connected.
298 * @exception std::bad_alloc The method might throw std::bad_alloc if
299 * memory is exhausted and the system throws in that case.
300 */
301 Callback::SafeFunctor connect(const Callback::SafeFunctor& f);
302
303 /**
304 * Connects a functor. It is thread safe.
305 * @param f The functor to connect.
306 * @param r A Releaser object for automatic disconnection of the
307 * functor if the object whose method it represents is destroyed.
308 * @return The functor connected.
309 * @exception std::bad_alloc The method might throw std::bad_alloc if
310 * memory is exhausted and the system throws in that case.
311 */
312 Callback::SafeFunctor connect(const Callback::SafeFunctor& f, Releaser& r);
313
314 /**
315 * Connects a callable object, such as formed by a lambda expression
316 * or the result of std::bind.
317 * @param f The callable object to connect. It must be fully bound
318 * (that is, take no arguments when called).
319 * @return A Callback::SafeFunctor object which can be passed to
320 * disconnect(), block() or unblock().
321 * @exception std::bad_alloc The method might throw std::bad_alloc if
322 * memory is exhausted and the system throws in that case. If might
323 * also throw if the copy or move constructor of the callable object
324 * throws.
325 *
326 * Since 2.1.0
327 */
328 // we need to use enable_if so that where this function is passed a
329 // Callback::SafeFunctor object or a pointer to a Callback::Callback
330 // object or some other convertible object, this templated overload is
331 // dropped from the overload set, in order to support the
332 // Callback::SafeFunctor overloads of this function. This overload
333 // calls into the version of this function taking a
334 // Callback::SafeFunctor object in order to perform type erasure.
335 template <class F,
336 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
337 const Callback::SafeFunctor>::value>::type>
338 Callback::SafeFunctor connect(F&& f) {
339 return connect(Callback::lambda<>(std::forward<F>(f)));
340 }
341
342 /**
343 * Connects a callable object, such as formed by a lambda expression
344 * or the result of std::bind.
345 * @param f The callable object to connect. It must be fully bound
346 * (that is, take no arguments when called).
347 * @param r A Releaser object for automatic disconnection of the
348 * callable object if an object whose method it represents or calls
349 * into is destroyed.
350 * @return A Callback::SafeFunctor object which can be passed to
351 * disconnect(), block() or unblock().
352 * @exception std::bad_alloc The method might throw std::bad_alloc if
353 * memory is exhausted and the system throws in that case. If might
354 * also throw if the copy or move constructor of the callable object
355 * throws.
356 *
357 * Since 2.1.0
358 */
359 // we need to use enable_if so that where this function is passed a
360 // Callback::SafeFunctor object or a pointer to a Callback::Callback
361 // object or some other convertible object, this templated overload is
362 // dropped from the overload set, in order to support the
363 // Callback::SafeFunctor overloads of this function. This overload
364 // calls into the version of this function taking a
365 // Callback::SafeFunctor object in order to perform type erasure.
366 template <class F,
367 class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type,
368 const Callback::SafeFunctor>::value>::type>
369 Callback::SafeFunctor connect(F&& f, Releaser& r) {
370 return connect(Callback::lambda<>(std::forward<F>(f)), r);
371 }
372
373 /**
374 * Disconnects a functor previously connected. This does not throw
375 * provided that the destructors of any bound arguments do not throw
376 * (as they should not do), and assuming that merely iterating through
377 * a list does not throw (as it would not on any sane implementation).
378 * It is thread safe.
379 * @param f The functor to disconnect.
380 */
381 void disconnect(const Callback::SafeFunctor& f);
382
383 /**
384 * Blocks a connected functor from executing in the main program
385 * thread when emit() or operator()() is called until unblock() is
386 * called. This method does not throw (assuming that merely iterating
387 * through a list does not throw, as it would not on any sane
388 * implementation). It is thread safe.
389 * @param f The functor to block.
390 * @note This has effect immediately: it will block a pending emission
391 * for which emit() or operator()() has previously been called but
392 * which has not yet been tested for execution in the main loop.
393 */
394 void block(const Callback::SafeFunctor& f);
395
396 /**
397 * Unblocks a previously blocked functor. This method does not throw
398 * (assuming that merely iterating through a list does not throw, as
399 * it would not on any sane implementation). It is thread safe.
400 * @param f The functor to unblock.
401 * @note This has effect immediately: it will unblock a pending
402 * emission for which emit() or operator()() has previously been
403 * called but which has not yet been tested for execution in the main
404 * loop.
405 */
406 void unblock(const Callback::SafeFunctor& f);
407
408 /**
409 * Initialises the program for the use of Notifier objects. It only
410 * needs to be called once at program start-up (it doesn't need to be
411 * called separately for each Notifier object), and can be called
412 * before any Notifier objects have been constructed. It should be
413 * called in the thread in which the default main glib event loop
414 * executes (the main program thread) before that thread creates any
415 * new threads.
416 * @exception std::bad_alloc This method might throw std::bad_alloc if
417 * memory is exhausted and the system throws in that case.
418 * @exception PipeError PipeError will be thrown if the static pipe
419 * used by Notifier objects cannot be initialised.
420 */
421 static void init();
422
423 /**
424 * The constructor is thread safe provided init() has previously been
425 * called before the main program thread creates any new threads.
426 * @exception std::bad_alloc The constructor might throw
427 * std::bad_alloc if memory is exhausted and the system throws in that
428 * case.
429 * @exception PipeError PipeError can be thrown if this is the first
430 * Notifier object to be constructed and Notifier::init() has not
431 * previously been called.
432 */
433 Notifier();
434
435 /**
436 * The destructor does not throw provided the destructors of any bound
437 * arguments do not throw and std::hash<T*>::operator()() does not
438 * throw (as it would not on any sane implementation). It is thread
439 * safe (but see the comments in the introductory remarks above about
440 * race conditions where the lifetime of a Notifier object is
441 * determined by a thread other than the main program thread).
442 */
443 ~Notifier();
444
445 /* Only has effect if --with-glib-memory-slices-compat or
446 * --with-glib-memory-slices-no-compat option picked */
447 CGU_GLIB_MEMORY_SLICES_FUNCS
448 };
449
450 } // namespace Cgu
451
452 #endif
Cgu::Notifier::operator=
Notifier & operator=(const Notifier &)=delete
Cgu
Definition: application.h:44
Cgu::Notifier::in_main_thread
bool in_main_thread() noexcept
Definition: notifier.h:250
Cgu::Notifier::init
static void init()
Cgu::Notifier::block
void block(const Callback::SafeFunctor &f)
Cgu::Notifier::~Notifier
~Notifier()
Cgu::Notifier::Notifier
Notifier()
io_watch.h
Cgu::Notifier
Provides thread-safe signalling between a worker thread and the main program thread.
Definition: notifier.h:214
Cgu::Notifier::disconnect
void disconnect(const Callback::SafeFunctor &f)
Cgu::Notifier::unblock
void unblock(const Callback::SafeFunctor &f)
Cgu::SafeEmitterArg
A thread-safe class to execute callbacks connected to it, with provision for automatic disconnection.
Definition: emitter.h:327
Cgu::Callback::SafeFunctorArg
Functor class holding a Callback::CallbackArg object, with thread-safe reference count.
Definition: callback.h:778
Cgu::Notifier::operator()
void operator()()
Definition: notifier.h:292
Cgu::PipeFifo
A wrapper for unix anonymous pipes.
Definition: pipes.h:150
Cgu::Notifier::emit
void emit()
CGU_GLIB_MEMORY_SLICES_FUNCS
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Cgu::Notifier::connect
Callback::SafeFunctor connect(const Callback::SafeFunctor &f)
Cgu::Releaser
A class used for tracking EmitterArg and SafeEmitterArg connections.
Definition: emitter.h:352
emitter.h
This file provides a thread-safe signal/slot mechanism, with automatic disconnection.
Cgu::Notifier::connect
Callback::SafeFunctor connect(F &&f)
Definition: notifier.h:338
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:117
pipes.h
cgu_config.h
Cgu::Notifier::connect
Callback::SafeFunctor connect(F &&f, Releaser &r)
Definition: notifier.h:369