c++-gtk-utils
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 
38 #include <pthread.h>
39 
40 #include <c++-gtk-utils/pipes.h>
41 #include <c++-gtk-utils/io_watch.h>
42 #include <c++-gtk-utils/emitter.h>
44 
45 namespace Cgu {
46 
47 /**
48  * @class Notifier notifier.h c++-gtk-utils/notifier.h
49  * @brief Provides thread-safe signalling between a worker thread and
50  * the main program thread.
51  * @sa Callback namespace Callback::post()
52  * @sa EmitterArg SafeEmitterArg Releaser
53  *
54  * The Notifier class provides thread-safe signalling between two
55  * threads. It does this through a pipe, to which an GSource (iowatch)
56  * object is attached to connect it to the glib program event loop. A
57  * functor is connected to the notifier, which is called in the
58  * receiving thread via the program event loop when operator()() (or
59  * emit()) is called on the Notifier object by the signalling thread.
60  * It therefore behaves like a SafeEmitter object, except that
61  * connected functors execute in the glib program event loop thread
62  * rather than in the thread which calls operator()()/emit().
63  *
64  * It is an alternative to the Callback::post() function in
65  * callback.h, and the documentation on callback.h contains a
66  * description of relevant trade-offs between the two.
67  *
68  * If the signalling thread is the same thread as that in which the
69  * functor connected to it will execute (which is the thread in which
70  * the default glib program event loop executes), executing it via the
71  * pipe would risk a deadlock - if the pipe fills up, the thread would
72  * block on write and never be able to read from the pipe to empty it.
73  * Accordingly, if the object is invoked by the same thread as that in
74  * which the functor will execute, this is detected and the functor
75  * will be invoked directly, rather than via the pipe. Therefore,
76  * actions so invoked may be out of order with those invoked by the
77  * other threads.
78  *
79  * If a Releaser object is passed as the second argument of
80  * Notifier::connect(), then a connected functor will automatically be
81  * disconnected if the object which has the Releaser object as a
82  * member is destroyed.
83  *
84  * The main use of Notifier objects is for a worker thread to signal
85  * an event to the main thread in which GTK+ is executing, which
86  * implies that GTK+ should also be executing in the default glib
87  * program event loop (GMainContext) (as will almost always be the
88  * case), which is the one with which the program first starts.
89  * Before a Notifier object is first used, it is a requirement that
90  * Notifier::init() (a static member function) be called in the thread
91  * in which the default glib event loop executes, and any connected
92  * functors will execute in that thread. Notifier::init() only needs
93  * to be called once at program start-up - it doesn't need to be
94  * called separately for each Notifier object, and can be called
95  * before any Notifier objects have been constructed. If it has not
96  * been called before the construction of the first Notifier object
97  * has taken place, it will occur automatically on that first
98  * construction. That means that if the first Notifier object is not
99  * constructed in the main (event loop) thread of the program, then
100  * Notifier::init() must be called explicitly before that first object
101  * is constructed. In addition, if glib < 2.32 is installed, before
102  * Notifier::init() is called (or the first Notifier object created)
103  * g_thread_init(0) should have been called: as a result a Notifier
104  * object cannot be a global (non-local) static object with glib <
105  * 2.32 (glib >= 2.32 does not require g_thread_init() to be called to
106  * be thread safe). Note also that global static Notifier objects are
107  * not safe prior to version 2.0.15, even with glib >= 2.32.
108  *
109  * It is a good idea that Notifier::init() should have been called (or
110  * the first Notifier object constructed) before the main program
111  * thread creates any new threads. Then the state of initialisation
112  * effected by Notifier::init() will automatically be visible between
113  * threads.
114  *
115  * When executing a functor connected to a Notifier object, a check is
116  * made for a case where between the signalling thread invoking a
117  * Notifier object and the main program event loop calling that
118  * functor, the Notifier object ceases to exist. However there can
119  * still be a race condition if the lifetime of the Notifier object is
120  * determined outside the thread of execution of the main program
121  * event loop and a Notifier object is destroyed by that other thread
122  * between the time the check is made and the functor executed.
123  * Normally Notifier objects are constructed and destroyed in the main
124  * program thread, but where that is not the case the user will need
125  * to take this into account and if need be provide appropriate
126  * synchronisation to secure the lifetime of the Notifier object until
127  * after the functor has been called. Likewise, a Releaser object
128  * cannot offer protection if the remote object whose non-static
129  * method is represented by a connected functor is destroyed by
130  * another thread while the main program loop is in the middle of
131  * executing the functor. When the main loop begins invoking the
132  * execution of the callback, the remote object must either wholly
133  * exist (in which case the callback will be invoked) or have been
134  * destroyed (in which case the callback will be ignored), and not be
135  * in some transient half-state governed by another thread.
136  *
137  * Apart from that, the Notifier object is thread-safe and any of its
138  * methods may be invoked in any thread. (It is as thread-safe as a
139  * SafeEmitter object, as described in emitter.h, which contains
140  * further details on thread safety.)
141  *
142  * To pass variable data to a functor executed by the Notifier object,
143  * the AsyncQueue class can be employed.
144 */
145 
146 /*
147  For a program with two GMainContext program event loops (not a usual
148  case), it would be possible for a Notifier-like object to be
149  initialised in the non-default GMainContext thread, and execute in
150  that thread, by passing that other GMainContext object as the last
151  argument when calling start_iowatch() in Notifier::Notifier().
152  However, to conserve file descriptors all Notifier objects share a
153  common pipe and iowatch event watch, which implies that all Notifier
154  objects would also need to execute in that other thread. To get
155  around this it would be possible either to templatize Notifier with
156  tag types for different GMainContexts (so that there would be a
157  different static pipe/iowatch object for each GMainContext), or to
158  have thread-local storage for each of the static objects in the
159  Notifier class, but an easier solution for one-off cases would be to
160  have a version of Notifier which does not use static (shared)
161  PipeFifo and iowatch objects, at the expense of greater use of file
162  descriptor resources.
163 
164  Such a special Notifier object could also be used to signal from a
165  Unix (asynchronous) signal/interrupt handler, but in that case the
166  write file descriptor of the pipe should be set non-blocking to
167  prevent the very unlikely but theoretically possible case (in a
168  program executing in a system under extreme load) of the pipe
169  filling up before being emptied by the Notifier::read_pipe_cb()
170  callback function executing in the main program and so blocking in
171  the handler, thus deadlocking the program.
172 */
173 
174 
175 namespace Thread {
176  class Mutex;
177 }
178 
179 class Notifier;
180 
181 class Notifier {
182 
183  static bool initialised;
184  static pthread_t thread_id;
185  // pointers can be keys of associative containers: "For templates
186  // greater, less, greater_equal, and less_equal, the specializations
187  // for any pointer type yield a total order, even if the built-in
188  // operators <, >, <=, >= do not." (para 20.3.3/8).
189  static std::unordered_set<Notifier*>* object_set_p;
190  static PipeFifo* pipe_p;
191  static Thread::Mutex* set_mutex_p;
192  static Thread::Mutex* write_mutex_p;
193  static void read_pipe_cb(bool&);
194 
195  SafeEmitter emitter;
196 public:
197 /**
198  * This class cannot be copied. The copy constructor is deleted.
199  */
200  Notifier(const Notifier&) = delete;
201 
202 /**
203  * This class cannot be copied. The assignment operator is deleted.
204  */
205  Notifier& operator=(const Notifier&) = delete;
206 
207 /**
208  * A utility which tells the caller whether it is in the thread in
209  * which the callback will execute (the main program thread). It will
210  * not throw. It is thread safe.
211  * @return true if the caller is in the thread in which the callback
212  * will execute, otherwise false.
213  */
214  // don't make this a static member function - it can then only be called
215  // by object notation after a Notifier object has first been constructed,
216  // which means Notifier::init() must have been called
217  bool in_main_thread() {return pthread_equal(thread_id, pthread_self());}
218 
219 /**
220  * This will cause the connected functors to be executed in the main
221  * program thread. It is thread safe (but see the comments in the
222  * introductory remarks above about race conditions where the lifetime
223  * of a Notifier object is determined by a thread other than the main
224  * program thread, and about protection by a Releaser object where a
225  * connected remote object is destroyed in mid-emission by another
226  * thread).
227  * @exception std::bad_alloc The method might throw std::bad_alloc if
228  * memory is exhausted and the system throws in that case, and this
229  * method is called in the thread in which the functors will execute
230  * (the main program thread). In addition, it will throw if the
231  * function or class methods represented by the functors throw (or if
232  * the assignment operator of a bound argument throws) and the call is
233  * made in that thread. If called in a different thread it will not
234  * throw (in that case, an exception thrown by a connected functor
235  * will be consumed to protect the glib main loop and the iowatch
236  * dispatcher will issue a g_critical() warning).
237  */
238  void emit();
239 
240 /**
241  * This will cause the connected functors to be executed in the main
242  * program thread. It is thread safe (but see the comments in the
243  * introductory remarks above about race conditions where the lifetime
244  * of a Notifier object is determined by a thread other than the main
245  * program thread, and about protection by a Releaser object where a
246  * connected remote object is destroyed in mid-emission by another
247  * thread).
248  * @exception std::bad_alloc The method might throw std::bad_alloc if
249  * memory is exhausted and the system throws in that case, and this
250  * method is called in the thread in which the functors will execute
251  * (the main program thread). In addition, it will throw if the
252  * function or class methods represented by the functors throw (or if
253  * the assignment operator of a bound argument throws) and the call is
254  * made in that thread. If called in a different thread it will not
255  * throw (in that case, an exception thrown by a connected functor
256  * will be consumed to protect the glib main loop and the iowatch
257  * dispatcher will issue a g_critical() warning).
258  */
259  void operator()() {emit();}
260 
261 /**
262  * Connects a functor. It is thread safe.
263  * @param f The functor to connect.
264  * @return The functor connected.
265  * @exception std::bad_alloc The method might throw std::bad_alloc if
266  * memory is exhausted and the system throws in that case.
267  */
269 
270 /**
271  * Connects a functor. It is thread safe.
272  * @param f The functor to connect.
273  * @param r A Releaser object for automatic disconnection of the
274  * functor if the object whose method it represents is destroyed.
275  * @return The functor connected.
276  * @exception std::bad_alloc The method might throw std::bad_alloc if
277  * memory is exhausted and the system throws in that case.
278  */
280 
281 /**
282  * Disconnects a functor previously connected. This does not throw
283  * provided that the destructors of any bound arguments do not throw
284  * (as they should not do), and assuming that merely iterating through
285  * a list does not throw (as it would not on any sane implementation).
286  * It is thread safe.
287  * @param f The functor to disconnect.
288  */
289  void disconnect(const Callback::SafeFunctor& f);
290 
291 /**
292  * Blocks a connected functor from executing in the main program
293  * thread when emit() or operator()() is called until unblock() is
294  * called. This method does not throw (assuming that merely iterating
295  * through a list does not throw, as it would not on any sane
296  * implementation). It is thread safe.
297  * @param f The functor to block.
298  * @note This has effect immediately: it will block a pending emission
299  * for which emit() or operator()() has previously been called but
300  * which has not yet been tested for execution in the main loop.
301  */
302  void block(const Callback::SafeFunctor& f);
303 
304 /**
305  * Unblocks a previously blocked functor. This method does not throw
306  * (assuming that merely iterating through a list does not throw, as
307  * it would not on any sane implementation). It is thread safe.
308  * @param f The functor to unblock.
309  * @note This has effect immediately: it will unblock a pending
310  * emission for which emit() or operator()() has previously been
311  * called but which has not yet been tested for execution in the main
312  * loop.
313  */
314  void unblock(const Callback::SafeFunctor& f);
315 
316 /**
317  * Initialises the program for the use of Notifier objects. It only
318  * needs to be called once at program start-up (it doesn't need to be
319  * called separately for each Notifier object), and can be called
320  * before any Notifier objects have been constructed. It should be
321  * called in the thread in which the default main glib event loop
322  * executes (the main program thread) before that thread creates any
323  * new threads.
324  * @exception std::bad_alloc This method might throw std::bad_alloc if
325  * memory is exhausted and the system throws in that case.
326  * @exception PipeError PipeError will be thrown if the static pipe
327  * used by Notifier objects cannot be initialised.
328  */
329  static void init();
330 
331 /**
332  * The constructor is thread safe provided init() has previously been
333  * called before the main program thread creates any new threads.
334  * @exception std::bad_alloc The constructor might throw
335  * std::bad_alloc if memory is exhausted and the system throws in that
336  * case.
337  * @exception PipeError PipeError can be thrown if this is the first
338  * Notifier object to be constructed and Notifier::init() has not
339  * previously been called.
340  */
341  Notifier();
342 
343 /**
344  * The destructor does not throw provided the destructors of any bound
345  * arguments do not throw and std::hash<T*>::operator()() does not
346  * throw (as it would not on any sane implementation). It is thread
347  * safe (but see the comments in the introductory remarks above about
348  * race conditions where the lifetime of a Notifier object is
349  * determined by a thread other than the main program thread).
350  */
351  ~Notifier();
352 
353 /* Only has effect if --with-glib-memory-slices-compat or
354  * --with-glib-memory-slices-no-compat option picked */
356 };
357 
358 } // namespace Cgu
359 
360 #endif
Cgu::Notifier::operator=
Notifier & operator=(const Notifier &)=delete
Cgu
Definition: application.h:44
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::in_main_thread
bool in_main_thread()
Definition: notifier.h:217
Cgu::Notifier
Provides thread-safe signalling between a worker thread and the main program thread.
Definition: notifier.h:181
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:308
Cgu::Callback::SafeFunctorArg
Functor class holding a Callback::CallbackArg object, with thread-safe reference count.
Definition: callback.h:726
Cgu::Notifier::operator()
void operator()()
Definition: notifier.h:259
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:333
emitter.h
This file provides a thread-safe signal/slot mechanism, with automatic disconnection.
Cgu::Thread::Mutex
A wrapper class for pthread mutexes.
Definition: mutex.h:117
pipes.h
cgu_config.h