future.h
Go to the documentation of this file.
/* Copyright (C) 2010 to 2015 Chris Vine
The library comprised in this file or of which this file is part is
distributed by Chris Vine under the GNU Lesser General Public
License as follows:
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public License
as published by the Free Software Foundation; either version 2.1 of
the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License, version 2.1, for more details.
You should have received a copy of the GNU Lesser General Public
License, version 2.1, along with this library (see the file LGPL.TXT
which came with this source code package in the src/utils sub-directory);
if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
However, it is not intended that the object code of a program whose
source code instantiates a template from this file or uses macros or
inline functions (of any length) should by reason only of that
instantiation or use be subject to the restrictions of use in the GNU
Lesser General Public License. With that in mind, the words "and
macros, inline functions and instantiations of templates (of any
length)" shall be treated as substituted for the words "and small
macros and small inline functions (ten lines or less in length)" in
the fourth paragraph of section 5 of that licence. This does not
affect any other reason why object code may be subject to the
restrictions in that licence (nor for the avoidance of doubt does it
affect the application of section 2 of that licence to modifications
of the source code in this file).
*/
#ifndef CGU_FUTURE_H
#define CGU_FUTURE_H
#include <memory>
#include <exception>
#include <utility> // for std::move and std::forward
#include <type_traits> // for std::remove_reference and std::remove_const
#include <pthread.h>
#include <glib.h>
#include <c++-gtk-utils/thread.h>
#include <c++-gtk-utils/mutex.h>
#include <c++-gtk-utils/callback.h>
#include <c++-gtk-utils/intrusive_ptr.h>
#include <c++-gtk-utils/shared_ptr.h>
#include <c++-gtk-utils/emitter.h>
#include <c++-gtk-utils/timeout.h>
#include <c++-gtk-utils/cgu_config.h>
namespace Cgu {
namespace Thread {
struct FutureThreadError: public std::exception {
virtual const char* what() const throw() {return "FutureThreadError\n";}
};
struct FutureWhenError: public std::exception {
virtual const char* what() const throw() {return "FutureWhenError\n";}
};
/**
* @class Cgu::Thread::Future future.h c++-gtk-utils/future.h
* @brief A class representing a pthread thread which will
* provide a value.
* @sa Cgu::Thread::Thread Cgu::Thread::JoinableHandle Cgu::AsyncResult Cgu::Thread::make_future() Cgu::Thread::TaskManager
*
* The Thread::Future class will launch a worker thread, run the
* function it represents in that thread until it returns, and store
* the return value so that it can be waited on and/or extracted by
* another thread. A new Thread::Future object representing the
* function to be called is normally created by calling
* Cgu::Thread::make_future() with a callable object, such as a lambda
* expression or the return value of std::bind. The worker thread is
* then started by calling run(), and the value extracted or waited
* for by calling get(). The run() method can only be called once,
* but any number of threads can wait for and/or extract the return
* value by calling the get() method. The class also provides a
* move_get() method, and a SafeEmitter @ref DoneEmitterAnchor
* "done_emitter" public object which emits when the worker thread has
* finished, and an associated when() function.
*
* The template parameter type of Thread::Future is the type of the
* return value of the function or callable object called by the
* Thread::Future object. The return value can be any type, including
* any arbitrarily large tuple or other struct or standard C++
* container.
*
* A Thread::Future object cannot represent a function with a void
* return type - a compilation error will result if that is attempted.
* If no return value is wanted, then the Thread::Thread class can be
* used directly. (However, if in a particular usage this class is
* thought to be more convenient, the function to be represented by it
* can be wrapped by another function which provides a dummy return
* value, such as a dummy int. One possible case for this is where
* more than one thread wants to wait for the worker thread to
* terminate, as pthread_join() and so Thread::Thread::join() only
* give defined behaviour when called by one thread.)
*
* A future object can also be constructed with Thread::make_future()
* and Thread::Future::make() functions which take a function pointer
* (or an object reference and member function pointer) with bound
* arguments, but these offer little advantage over using std::bind,
* so generally it is easier to pass a callable object. These
* functions can take up to three bound arguments in the case of a
* non-static member function, and four bound arguments in the case of
* any other function. In the case of a non-static member function,
* the referenced object whose member function is to be called must
* remain in existence until the worker thread has completed. The
* target function passed by pointer (or member function pointer) can
* take a reference to const argument, as a copy of the object to be
* passed to the argument is taken to avoid dangling references, but
* it cannot take a reference to non-const argument.
*
* It is to be noted that the target function or callable object to be
* represented by a Thread::Future object must not allow any exception
* other than Thread::Exit, an exception deriving from std::exception
* or a cancellation pseudo-exception to escape from it when it is
* executed. This includes ensuring that, for any function's bound
* argument which is of class type and not taken by reference, the
* argument's copy constructor does not throw anything other than
* these, and that the move assignment operator (or if none, copy
* assignment operator) of the return value (if of class type) of the
* target function or callable object does not throw anything other
* than these. (If the target function or callable object, or the
* copy constructor of a bound value argument or the move or copy
* assignment operator of the return value, throws Thread::Exit or an
* exception deriving from std::exception, the exception is safely
* consumed and the Thread::Future object's error flag is set.
* However, if the move assignment operator or copy assignment
* operator, as the case may be, of the return value throws, it should
* leave the movee/assignee in a state in which it can safely be
* destroyed and in which, if that movee/assignee is further copied or
* moved from, the copy or move either throws an exception or produces
* an object which can also be destroyed -- but these are minimum
* requirements for any reasonable assignment operator, and met by any
* assignment operator offering the basic exception guarantee.)
*
* The Thread::Future object will store the return value of the target
* function or callable object, so that it is available to the get()
* and move_get() methods and any 'when' callback, and therefore
* either move it, or if it has no move assignment operator, copy it
* once.
*
* For safety reasons, the get() method returns by value and so will
* cause the return value to be copied once more, so for return values
* comprising complex class objects which are to be extracted using
* the get() method, it is often better if the function represented by
* the Thread::Future object allocates the return value on free store
* and returns it by pointer, by Cgu::SharedLockPtr, or by a
* std::shared_ptr implementation which has a thread-safe reference
* count. Alternatively, from version 2.0.11 a move_get() method is
* provided which will make a move operation instead of a copy if the
* return type implements a move constructor, but see the
* documentation on move_get() for the caveats with respect to its
* use: in particular, if move_get() is to be called by a thread, then
* get() may not normally be called by another thread, nor should the
* when() method be called.
*
* It should be noted that where the when() method is used, the return
* value is passed to the 'when' callback by reference to const and so
* without the copying carried out by the get() method: therefore, if
* the return value has a move assignment operator and the when()
* method is to be employed, and the 'when' callback only needs to
* call const methods of the return value, it may be more efficient
* not to allocate the return value on free store.
*
* This is a usage example:
*
* @code
* std::vector<long> get_primes(int n); // calculates the first n primes
*
* // get the first 1,000 primes
* using namespace Cgu;
*
* auto future = Thread::make_future([] () {return get_primes(1000);});
*
* future->run();
* ... [ do something else ] ...
* std::vector<long> result(future->move_get());
* std::for_each(result.begin(), result.end(), [](long l) {std::cout << l << std::endl;});
* @endcode
*
* The Cgu::Thread::Future::when() functions
* -----------------------------------------
*
* From version 2.0.2, the return value of the thread function
* represented by Cgu::Thread::Future can be obtained asynchronously
* using Cgu::Thread::Future::when() to execute a function in a glib
* main loop when the thread function completes. The above example
* could be reimplemented as:
*
* @code
* std::vector<long> get_primes(int n); // calculates the first n primes
*
* using namespace Cgu;
*
* auto future = Thread::make_future([] () {return get_primes(1000);});
* auto w = [](const std::vector<long>& vec) {
* for (const auto& elt: vec) {std::cout << elt << std::endl;}
* };
* future->when(Callback::lambda<const std::vector<long>>(std::move(w)));
* future->run();
* @endcode
*
* The Cgu::Thread::Future::fail() functions
* -----------------------------------------
*
* The Thread::Future::when() functions have an associated optional
* Thread::Future::fail() function which causes a 'fail' callback to
* execute in a glib main loop in the event of certain exceptions
* arising in executing the thread function or a thread being
* cancelled (the documentation on Thread::Future::fail() gives
* further details). The 'fail' callback must be fully bound. Whilst
* a worker thread can pass error status to the 'fail' callback via
* shared data bound to both the thread function and the 'fail'
* callback (held by, say, a SharedLockPtr object), or a global error
* stack, 'fail' callbacks are generally best reserved either for use
* with entirely unexpected exceptions, where the most reasonable
* course is to perform some orderly logging and shutdown, or to
* report thread cancellation. For handlable exceptions, in an
* asynchronous environment the best course is often to catch them and
* deal with them in the thread function itself and return a value of
* the return type for the 'when' callback indicating no result.
*/
#ifndef DOXYGEN_PARSING
namespace FutureHelper {
// the sole purpose of this struct is to enable a callback object to
// be constructed with Callback::make_ref() which takes an argument
// which can be mutated when the callback is executed. Normally this
// would be unsafe: however in this particular use it is fine as the
// callback is only ever executed once, via Future::run().
template <class Val>
struct WhenWrapperArg {
mutable std::unique_ptr<const Cgu::Callback::CallbackArg<const Val&>> when;
// TODO: these constructors are a work-around for a bug in gcc <
// 4.6. At any API break where the required version of gcc is
// increased to gcc-4.6 or higher, remove them.
WhenWrapperArg(std::unique_ptr<const Cgu::Callback::CallbackArg<const Val&>>&& when_) :
when(std::move(when_)) {}
WhenWrapperArg(WhenWrapperArg&& w): when(std::move(w.when)) {}
};
// the sole purpose of this struct is to enable a callback object to
// be constructed with Callback::make_ref() which takes an argument
// which can be mutated when the callback is executed. Normally this
// would be unsafe: however in this particular use it is fine as the
// callback is only ever executed once, via Future::run().
template <class Val>
struct WhenWrapperArgRel {
mutable std::unique_ptr<Cgu::SafeEmitterArg<const Val&>> when;
// TODO: these constructors are a work-around for a bug in gcc <
// 4.6. At any API break where the required version of gcc is
// increased to gcc-4.6 or higher, remove them.
WhenWrapperArgRel(std::unique_ptr<Cgu::SafeEmitterArg<const Val&>>&& when_) :
when(std::move(when_)) {}
WhenWrapperArgRel(WhenWrapperArgRel&& w): when(std::move(w.when)) {}
};
} // namespace FutureHelper
#endif // DOXYGEN_PARSING
template <class Val>
class Future: public IntrusiveLockCounter {
std::unique_ptr<Cgu::Thread::Thread> thread_u;
std::unique_ptr<Cgu::Callback::Callback> cb_u;
mutable Mutex mutex;
Cond cond;
Val val;
bool done;
bool running;
bool error;
bool emitter_error;
template <class T, class Ret, class... Args>
void run_wrapper(T*, Ret (T::*)(Args...), const Args&...);
template <class T, class Ret, class... Args>
void run_wrapper_const(const T*, Ret (T::*)(Args...) const, const Args&...);
template <class Ret, class... Args>
void run_wrapper_static(Ret (*)(Args...), const Args&...);
template <class Func>
void run_wrapper_functor(Func&);
void cancel_cleanup();
void execute_done(const std::unique_ptr<const Cgu::Callback::CallbackArg<const Val&>>&);
void post_done(const FutureHelper::WhenWrapperArg<Val>&,
gint, GMainContext*);
void execute_done_rel(const std::unique_ptr<Cgu::SafeEmitterArg<const Val&>>&);
void post_done_rel(const FutureHelper::WhenWrapperArgRel<Val>&,
gint, GMainContext*);
// this is a static function taking the future object by IntrusivePtr to
// ensure that the future object remains in existence whilst this
// function might execute
static void fail_cb(const Cgu::IntrusivePtr<Future<Val>>& future,
const std::unique_ptr<const Cgu::Callback::Callback>& func,
bool& ret);
// private constructor - this class can only be created with Thread::Future::make()
Future(): val(), done(false), running(false), error(false), emitter_error(false) {}
public:
// this class cannot be copied except by smart pointer
/**
* This class cannot be copied (except by smart pointer). The copy
* constructor is deleted.
*/
Future(const Future&) = delete;
/**
* This class cannot be copied (except by smart pointer). The
* assignment operator is deleted.
*/
Future& operator=(const Future&) = delete;
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the default constructor of the
* return value type throws.
*/
template <class Ret, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(T& t,
Ret (T::*func)());
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of the bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Arg1, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(T& t,
Ret (T::*func)(Param1),
Arg1&& arg1);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Arg1, class Arg2, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(T& t,
Ret (T::*func)(Param1, Param2),
Arg1&& arg1,
Arg2&& arg2);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Param3,
class Arg1, class Arg2, class Arg3, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(T& t,
Ret (T::*func)(Param1, Param2, Param3),
Arg1&& arg1,
Arg2&& arg2,
Arg3&& arg3);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the default constructor of the
* return value type throws.
*/
template <class Ret, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(const T& t,
Ret (T::*func)() const);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of the bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Arg1, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(const T& t,
Ret (T::*func)(Param1) const,
Arg1&& arg1);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Arg1, class Arg2, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(const T& t,
Ret (T::*func)(Param1, Param2) const,
Arg1&& arg1,
Arg2&& arg2);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Param3,
class Arg1, class Arg2, class Arg3, class T>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(const T& t,
Ret (T::*func)(Param1, Param2, Param3) const,
Arg1&& arg1,
Arg2&& arg2,
Arg3&& arg3);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the default constructor of the
* return value type throws.
*/
template <class Ret>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Ret (*func)());
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of the bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Arg1>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Ret (*func)(Param1),
Arg1&& arg1);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Arg1, class Arg2>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Ret (*func)(Param1, Param2),
Arg1&& arg1,
Arg2&& arg2);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Param3,
class Arg1, class Arg2, class Arg3>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Ret (*func)(Param1, Param2, Param3),
Arg1&& arg1,
Arg2&& arg2,
Arg3&& arg3);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type throws.
*/
template <class Ret, class Param1, class Param2, class Param3, class Param4,
class Arg1, class Arg2, class Arg3, class Arg4>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Ret (*func)(Param1, Param2, Param3, Param4),
Arg1&& arg1,
Arg2&& arg2,
Arg3&& arg3,
Arg4&& arg4);
/**
* Constructs a new Cgu::Thread::Future object (returned by
* Cgu::IntrusivePtr<Cgu::Thread::Future<Val>>). The type parameter
* Val represents the return value of the function to be represented
* by the new object. From version 2.0.4, it will usually be more
* convenient to call the Cgu::Thread::make_future() function, which
* is a convenience wrapper for this static method.
* @param functor The callable object to be executed. It should
* return the Val type.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note 1. This method will also throw if the copy or move
* constructor of the callable object passed as an argument throws, or
* the default constructor of the return value type throws.
* @note 2. If the callable object passed as an argument has both
* const and non-const operator()() methods, the non-const version
* will be called even if the callable object passed is a const
* object.
*/
template <class Func>
static Cgu::IntrusivePtr<Cgu::Thread::Future<Val>> make(Func&& functor);
/**
* Runs the function or callable object represented by this
* Cgu::Thread::Future object in a new worker thread. That function
* will only be run once. If this is the first time this method has
* been called, it will start the worker thread and return true, and
* if it has previously been called, this method will do nothing and
* return false. This method will not wait for the worker thread to
* complete before returning. This method is thread safe and may be
* called by a different thread from the one which called make().
* @return true if this is the first time this method has been called,
* or false if this method has previously been called.
* @exception Cgu::Thread::FutureThreadError This method might throw
* Cgu::Thread::FutureThreadError if it has not previously been called
* and the thread did not start properly. If it does throw, this
* Cgu::Thread::Future object is defunct and further attempts to call
* this method will return immediately with a false value. (It is
* often not worth checking for this exception, as it means either
* memory is exhausted, the pthread thread limit has been reached or
* pthread has run out of other resources to start new threads.)
* @exception std::bad_alloc This method might throw std::bad_alloc if
* it has not previously been called, and memory is exhausted and the
* system throws in that case. If it does throw, this
* Cgu::Thread::Future object is defunct and further attempts to call
* this method will return immediately with a false value. (This
* exception will not be thrown if the library has been installed
* using the \--with-glib-memory-slices-no-compat configuration
* option: instead glib will terminate the program if it is unable to
* obtain memory from the operating system.)
* @note 1. Any Cgu::Thread::Exit exception, or any uncaught exception
* derived from std::exception, which is thrown from the worker thread
* will be caught and consumed and the error flag will be set. The
* worker thread will safely terminate and unwind the stack in so
* doing.
* @note 2. As this wrapper class can provide error reporting in a way
* that Cgu::Thread::Thread of itself cannot, it would be desirable to
* consume any other uncaught exceptions. However, this cannot be
* done: annoyingly, NPTL's forced stack unwinding does not allow this
* if thread cancellation is to be made available. If an uncaught
* exception propagates out of a thread when the thread exits, the
* C++11/14 standard will cause std::terminate() to be called and so
* terminate the entire program. Accordingly, a user must make sure
* that no exceptions, other than Cgu::Thread::Exit or those derived
* from std::exception or any cancellation pseudo-exception, can
* propagate from the function which this Cgu::Thread::Future object
* represents, nor from the copy constructor of any argument type that
* that function takes by value nor from the move assignment operator
* (or if none, copy assignment operator) of the return value of that
* function.
* @note 3. If the worker thread is cancelled by a call to cancel()
* while in the middle of executing the function which this
* Cgu::Thread::Future object represents, the error flag will be set.
*/
bool run();
/**
* Gets the stored value obtained from the function or callable object
* which is represented by this object. If the worker thread launched
* by the call to run() has not completed, then this method will block
* until it has completed. If run() has not been called, then run()
* will be called (and this method will block until the launched
* worker thread completes). If the function or callable object which
* is represented by this Cgu::Thread::Future object throws
* Cgu::Thread::Exit or an uncaught exception derived from
* std::exception, or if any of those exceptions are thrown either by
* the copy constructor of an argument taken by value by that function
* or object, or by the move assignment operator (or if none, copy
* assignment operator) of the return value of that function or
* object, then the exception will have been consumed by this
* Cgu::Thread::Future object and the error flag will have been set.
* The error flag will also have been set if the worker thread is
* cancelled or the thread wrapper in this Cgu::Thread::Future object
* threw std::bad_alloc. On the error flag being set, this method
* will unblock and return a default constructed object of the return
* type. This method is thread safe and may be called by any thread
* (and by more than one thread). It is a cancellation point if it
* blocks, and from version 2.0.11 is cancellation safe if the stack
* unwinds on cancellation. It is also strongly exception safe: no
* data will be lost if extracting the value fails.
* @return The value obtained from the function which is represented
* by this object, or a default constructed object of the return type
* if the error flag has been set.
* @exception Cgu::Thread::FutureThreadError This method might throw
* Cgu::Thread::FutureThreadError if run() has not previously been
* called and the thread did not start properly when this function
* called run().
* @exception std::bad_alloc This method might throw std::bad_alloc if
* run() has not previously been called, memory is exhausted and the
* system throws in that case. (This exception will not be thrown if
* the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @note 1. This method might also throw if the copy constructor of
* the returned value type throws.
* @note 2. Question: Couldn't this method return the stored value by
* lvalue reference to const? Answer: It could. However, because of
* return value optimization, which will be implemented by any
* compiler capable of compiling this library, no advantage would be
* gained by doing so when initializing a local variable with the
* return value of this method (the copy constructor will only be
* called once whether returning by value or const reference). The
* advantage of returning by value is that the call to the copy
* constructor is forced to be within this Thread::Future object's
* mutex, so different threads' calls to the copy constructor are
* serialized, and also with blocked cancellation, so this method is
* cancellation safe. All calls to this method by different threads
* are therefore isolated and we do not have to worry about the thread
* safety of direct access to the stored value via its const methods
* outside the mutex (which would not be thread safe if the stored
* value has data members declared mutable) nor about the cancellation
* safety of the copy constructor. Of course, for objects which do
* not have mutable data, a hit arises by returning by value in cases
* where it is not intended to initialize a local variable at all nor
* to cancel a thread: where, say, only const methods are to be called
* on the return value (which could be done directly if this method
* returned by const reference). However, in many use cases this will
* be mitigated by the move_get() method.
*/
Val get();
/**
* Gets the stored value obtained from the function or callable object
* which is represented by this object by a move operation, if the
* return type implements a move constructor (otherwise this method
* does the same as the get() method). It is provided as an option
* for cases where a move is required for efficiency reasons, but
* although it may be called by any thread, a move from this
* Thread::Future object may normally only be made once (except where
* the return type has been designed to be moved more than once for
* the limited purpose of inspecting a flag indicating whether its
* value is valid or not). If this method is to be called then no
* calls to get() by another thread should normally be made and no
* calls to when() should be made. If the worker thread launched by
* the call to run() has not completed, then this method will block
* until it has completed. If run() has not been called, then run()
* will be called (and this method will block until the launched
* worker thread completes). If the function or callable object which
* is represented by this Cgu::Thread::Future object throws
* Cgu::Thread::Exit or an uncaught exception derived from
* std::exception, or if any of those exceptions are thrown either by
* the copy constructor of an argument taken by value by that function
* or object, or by the move assignment operator (or if none, copy
* assignment operator) of the return value of that function or
* object, then the exception will have been consumed by this
* Cgu::Thread::Future object and the error flag will have been set.
* The error flag will also have been set if the worker thread is
* cancelled or the thread wrapper in this Cgu::Thread::Future object
* threw std::bad_alloc. On the error flag being set, this method
* will unblock and return a default constructed object of the return
* type. This method is a cancellation point if it blocks, and is
* cancellation safe if the stack unwinds on cancellation. This
* method is only exception safe if the return type's move constructor
* is exception safe.
* @return The value obtained from the function which is represented
* by this object, or a default constructed object of the return type
* if the error flag has been set.
* @exception Cgu::Thread::FutureThreadError This method might throw
* Cgu::Thread::FutureThreadError if run() has not previously been
* called and the thread did not start properly when this function
* called run().
* @exception std::bad_alloc This method might throw std::bad_alloc if
* run() has not previously been called, memory is exhausted and the
* system throws in that case. (This exception will not be thrown if
* the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @note 1. This method might also throw if the copy or move
* constructor of the returned value type throws.
* @note 2. Question: Couldn't this method return the stored value by
* rvalue reference? Answer: It could. However, because of return
* value optimization, which will be implemented by any compiler
* capable of compiling this library, no advantage would be gained by
* doing so when initializing a local variable with the return value
* of this method (the move constructor will only be called once, and
* no call will be made to the copy constructor, whether returning by
* value or rvalue reference). The advantage of returning by value is
* that the call to the move constructor is forced to be within this
* Thread::Future object's mutex, so different threads' calls to the
* move constructor are serialized, and also with blocked
* cancellation, so this method is cancellation safe. All calls to
* this method by different threads are therefore isolated and we do
* not have to worry about the thread safety of the mutating first
* call to this method, nor about direct access to the stored value
* via a rvalue reference outside the mutex nor the cancellation
* safety of the move constructor.
*
* Since 2.0.11
*/
Val move_get();
/**
* Cancels the worker thread in which the function or callable object
* represented by this object runs, if it has not yet finished. If
* this method is called and the worker thread is still running and is
* cancelled in response to a call to this method, then the error flag
* will be set so that a method calling get() or move_get() can
* examine whether the result is valid. If run() has not yet been
* called or the worker thread has already finished executing the
* function or callable object represented by this object then this
* function does nothing and returns false. This method is thread
* safe and may be called by any thread. It will not throw.
* @return true if run() has previously been called and the worker
* thread has not yet finished executing the function or callable
* object represented by this object, otherwise false (in which case
* this method does nothing).
* @note 1. Use this method with care. When cancelling a thread not
* all thread implementations will unwind the stack, and so run the
* destructors of local objects. This is discussed further in the
* documentation on Cgu::Thread::Thread::cancel().
* @note 2. This method might return true because the worker thread
* has not yet finished, but the error flag might still not be set.
* This is because the worker thread may not meet a cancellation point
* before it ends naturally. It is the error flag which indicates
* definitively whether the worker thread terminated prematurely in
* response to a call to this method.
*/
bool cancel();
/**
* A utility enabling the value returned by the thread function
* represented by this Cgu::Thread::Future object to be dealt with
* asynchronously rather than by (or in addition to) a call to the
* get() method. It causes the callback passed as an argument to this
* method (referred to below as the 'when' callback) to be executed by
* a thread's main loop if and when the thread function represented by
* this Cgu::Thread::Future object finishes correctly - the 'when'
* callback is passed that thread function's return value when it is
* invoked. This method is thread safe, and may be called by any
* thread.
*
* This functionality is implemented by connecting an internal
* dispatching callback to the done_emitter object.
*
* The 'when' callback should take a single unbound argument
* comprising a const reference to the return type of the thread
* function represented by this Cgu::Thread::Future object. (So, in
* the case of a Future<int> object, the callback function should take
* a const int& argument as the unbound argument.) The 'when'
* callback can have any number of bound arguments, except that a
* bound argument may not include a copy of this Cgu::Thread::Future
* object held by intrusive pointer as returned by the make() methods
* (that would result in this Cgu::Thread::Future object owning, via
* done_emitter, a reference to itself and so become incapable of
* being freed). The 'when' callback may, however, take a pointer to
* this Cgu::Thread::Future object, as obtained by the
* Cgu::IntrusivePtr::get() method, because this Cgu::Thread::Future
* object is guaranteed to remain in existence until the callback has
* completed executing.
*
* This method cannot be called after the thread function represented
* by this Cgu::Thread::Future object has completed (either
* successfully or unsuccessfully) so that is_done() would return
* true, and if this is attempted a Cgu::Thread::FutureWhenError
* exception will be thrown. Therefore, generally this method should
* be called before the run() method has been called.
*
* Once the run() method has been called, this Cgu::Thread::Future
* object will always stay in existence until the thread function
* represented by it has completed (whether correctly, by cancellation
* or by a thrown exception), and any 'when' callback (and any other
* callbacks connected to the done_emitter object) and any 'fail'
* callback have completed. Accordingly it is safe to use this method
* even if the intrusive pointer object returned by the make() methods
* will go out of scope before the 'when' callback has executed: the
* callback will execute correctly irrespective of that.
*
* Summary: use of this method is safe and has been implemented in a
* way which does not give rise to timing issues.
*
* If memory is exhausted and std::bad_alloc is thrown by the thread
* wrapper of Cgu::Thread::Future after run() is called or by
* done_emitter when emitting, or if the thread function represented
* by this Cgu::Thread::Future object throws Cgu::Thread::Exit, is
* cancelled, exits with an uncaught exception deriving from
* std::exception, takes an argument by value whose copy constructor
* throws such an exception or has a return value whose move
* assignment operator (or if none, copy assignment operator) throws
* such an exception, or if the 'when' callback represents a function
* taking a non-reference argument whose copy constructor throws an
* exception, or if any other callback has been connected to
* done_emitter before this method is called which exits with an
* uncaught exception, then the 'when' callback will not execute
* (instead the exception concerned will be consumed and an error
* indicated). With many systems, swap memory combined with memory
* over-commit makes it pointless to check for std::bad_alloc (and
* even more so in programs using glib, as glib aborts a program where
* it cannot obtain memory from the operating system). So subject to
* that, if the user program is designed so that the thread function
* represented by this Cgu::Thread::Future object does not exit with
* uncaught exceptions, does not take an argument by value which
* throws, does not have a return value whose move assignment operator
* (or if none, copy assignment operator) throws, does not throw
* Cgu::Thread::Exit and is not cancelled, and so that the 'when'
* callback does not exit with an uncaught exception (and a function
* represented by that callback either takes no arguments of class
* type by value or the copy constructors of any of its value
* arguments do not throw), and if this method is called before any
* other callbacks are connected to done_emitter, the possibility of
* failure can be disregarded.
*
* In cases where that is not true and detecting whether a failure has
* occurred is required, a fail() method is provided. It should be
* noted that a callback handed to the fail() method will not execute
* in a case of error if the error comprises the 'when' callback
* exiting with an uncaught exception when it is executed by the main
* loop, or the copy constructor of any value argument of a function
* represented by the 'when' callback throwing (such exceptions would
* be consumed internally in order to protect the main loop and a
* g_critical message issued). If the 'when' callback might exit with
* an uncaught exception when executing or have the copy constructor
* of a value argument throw, and doing something other than consuming
* the exception and issuing a g_critical message is required, then a
* different approach is to start a new thread to wait on the get()
* method which can act on the result of is_error() directly.
*
* If glib < 2.32 is used, the glib main loop must have been made
* thread-safe by a call to g_thread_init() before this function is
* called. glib >= 2.32 does not require g_thread_init() to be called
* in order to be thread safe.
*
* @param cb The 'when' callback (the callback to be executed when the
* function represented by this Cgu::Thread::Future object has
* successfully completed). Ownership is taken of this object, and it
* will be deleted when it has been finished with.
* @param priority The priority to be given to the 'when' callback in
* the main loop after the thread function represented by this
* Cgu::Thread::Future object has successfully completed. In
* ascending order of priorities, priorities are G_PRIORITY_LOW,
* G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE, G_PRIORITY_DEFAULT
* and G_PRIORITY_HIGH. The default is G_PRIORITY_DEFAULT. This
* determines the order in which the callback will appear in the event
* list in the main loop, not the priority which the OS will adopt.
* @param context The glib main context of the thread in whose main
* loop the 'when' callback is to be executed (the default of NULL
* will cause the callback to be executed in the main program loop).
* @return The internal dispatching callback created by this method
* and connected to done_emitter. It is made available as a return
* value so that if wanted it can be disconnected programmatically
* from done_emitter, or block()/unblock() can be called on it (but if
* that is to be done, it must be done before the thread function
* represented by this Cgu::Thread::Future object has completed in
* order for it to be effective).
* @exception Cgu::Thread::FutureWhenError This method will throw
* Cgu::Thread::FutureWhenError if it is called after the thread
* function represented by this Cgu::Thread::Future object has
* completed. If it does so, the 'when' callback will be disposed of.
* @exception std::bad_alloc This method might throw std::bad_alloc if
* memory is exhausted and the system throws in that case. If it does
* so, the 'when' callback will be disposed of.
* @note The return value of the function represented by this
* Cgu::Thread::Future object is stored and passed as an argument to
* the 'when' callback by const reference. If other threads might
* concurrently call this object's get() method, which copies the
* stored value, the stored type's copy constructor must be thread
* safe with respect to the stored type's const methods. This would
* be relevant if the stored type has data members declared mutable
* which would be copied by its copy constructor.
*
* Since 2.0.2
*/
Cgu::Callback::SafeFunctor when(const Cgu::Callback::CallbackArg<const Val&>* cb,
gint priority = G_PRIORITY_DEFAULT,
GMainContext* context = 0);
/**
* This is a version of the utility enabling the value returned by the
* thread function represented by this Cgu::Thread::Future object to
* be dealt with asynchronously, which takes a Releaser object for
* automatic disconnection of the callback passed as an argument to
* this method (referred to below as the 'when' callback), if the
* object having the 'when' callback function as a member is
* destroyed. For this to be race free, the lifetime of that object
* must be controlled by the thread in whose main loop the 'when'
* callback will execute.
*
* If the 'when' callback has not been released, this method causes it
* to be executed by a thread's main loop if and when the thread
* function represented by this Cgu::Thread::Future object finishes
* correctly - the 'when' callback is passed that thread function's
* return value when it is invoked. This method is thread safe, and
* may be called by any thread.
*
* This functionality is implemented by connecting an internal
* dispatching callback to the done_emitter object.
*
* The 'when' callback should take a single unbound argument
* comprising a const reference to the return type of the thread
* function represented by this Cgu::Thread::Future object. (So, in
* the case of a Future<int> object, the callback function should take
* a const int& argument as the unbound argument.) The 'when'
* callback can have any number of bound arguments, except that a
* bound argument may not include a copy of this Cgu::Thread::Future
* object held by intrusive pointer as returned by the make() methods
* (that would result in this Cgu::Thread::Future object owning, via
* done_emitter, a reference to itself and so become incapable of
* being freed). The 'when' callback may, however, take a pointer to
* this Cgu::Thread::Future object, as obtained by the
* Cgu::IntrusivePtr::get() method, because this Cgu::Thread::Future
* object is guaranteed to remain in existence until the callback has
* completed executing.
*
* This method cannot be called after the thread function represented
* by this Cgu::Thread::Future object has completed (either
* successfully or unsuccessfully) so that is_done() would return
* true, and if this is attempted a Cgu::Thread::FutureWhenError
* exception will be thrown. Therefore, generally this method should
* be called before the run() method has been called.
*
* The documentation for the version of this method which does not
* take a Releaser object gives further details of how this method is
* used.
*
* If glib < 2.32 is used, the glib main loop must have been made
* thread-safe by a call to g_thread_init() before this function is
* called. glib >= 2.32 does not require g_thread_init() to be called
* in order to be thread safe.
*
* @param cb The 'when' callback (the callback to be executed when the
* function represented by this Cgu::Thread::Future object has
* successfully completed). Ownership is taken of this object, and it
* will be deleted when it has been finished with.
* @param r A Releaser object for automatic disconnection of the
* 'when' callback before it executes in a main loop (mainly relevant
* if the callback represents a non-static member function of an
* object which may be destroyed before the callback executes).
* @param priority The priority to be given to the 'when' callback in
* the main loop after the thread function represented by this
* Cgu::Thread::Future object has successfully completed. In
* ascending order of priorities, priorities are G_PRIORITY_LOW,
* G_PRIORITY_DEFAULT_IDLE, G_PRIORITY_HIGH_IDLE, G_PRIORITY_DEFAULT
* and G_PRIORITY_HIGH. The default is G_PRIORITY_DEFAULT. This
* determines the order in which the callback will appear in the event
* list in the main loop, not the priority which the OS will adopt.
* @param context The glib main context of the thread in whose main
* loop the 'when' callback is to be executed (the default of NULL
* will cause the callback to be executed in the main program loop).
* @return The internal dispatching callback created by this method
* and connected to done_emitter. It is made available as a return
* value so that if wanted it can be disconnected programmatically
* from done_emitter, or block()/unblock() can be called on it (but if
* that is to be done, it must be done before the thread function
* represented by this Cgu::Thread::Future object has completed in
* order for it to be effective).
* @exception Cgu::Thread::FutureWhenError This method will throw
* Cgu::Thread::FutureWhenError if it is called after the thread
* function represented by this Cgu::Thread::Future object has
* completed. If it does so, the 'when' callback will be disposed of.
* @exception std::bad_alloc This method might throw std::bad_alloc if
* memory is exhausted and the system throws in that case. If it does
* so, the 'when' callback will be disposed of.
* @exception Cgu::Thread::MutexError This method will throw
* Cgu:Thread::MutexError if initialisation of the mutex in a
* SafeEmitterArg object constructed by this method fails. If it does
* so, the 'when' callback will be disposed of. (It is often not
* worth checking for this, as it means either memory is exhausted or
* pthread has run out of other resources to create new mutexes.)
* @note 1. The return value of the function represented by this
* Cgu::Thread::Future object is stored and passed as an argument to
* the 'when' callback by const reference. If other threads might
* concurrently call this object's get() method, which copies the
* stored value, the stored type's copy constructor must be thread
* safe with respect to the stored type's const methods. This would
* be relevant if the stored type has data members declared mutable
* which would be copied by its copy constructor.
* @note 2. By virtue of the Releaser object, it is in theory possible
* (if memory is exhausted and the system throws in that case) that an
* internal SafeEmitterArg object will throw std::bad_alloc when
* emitting/executing the 'when' callback in the glib main loop, with
* the result that the relevant callback will not execute (instead the
* exception will be consumed and a g_critical() warning will be
* issued). This is rarely of any relevance because glib will abort
* the program if it is itself unable to obtain memory from the
* operating system. However, where it is relevant, design the
* program so that it is not necessary to provide a releaser object.
*
* Since 2.0.2
*/
Cgu::Callback::SafeFunctor when(const Cgu::Callback::CallbackArg<const Val&>* cb,
Cgu::Releaser& r,
gint priority = G_PRIORITY_DEFAULT,
GMainContext* context = 0);
/**
* A utility intended to be used where relevant in conjunction with
* the when() methods. It enables a callback to be executed in a glib
* main loop (referred to below as the 'fail' callback) if memory is
* exhausted and std::bad_alloc was thrown by the thread wrapper of
* Cgu::Thread::Future after calling run() or by done_emitter when
* emitting, or if the thread function represented by this
* Cgu::Thread::Future object threw Cgu::Thread::Exit, exited with an
* uncaught exception deriving from std::exception or was cancelled
* (or that function took an argument of class type by value whose
* copy constructor threw such an exception or had a return value of
* class type whose move assignment operator, or if none copy
* assignment operator, threw such an exception), or any callback
* connected to done_emitter exited with an uncaught exception. It
* therefore enables errors to be detected and acted on without having
* a thread wait on the get() method in order to test is_error() or
* is_emitter_error().
*
* It is implemented by attaching a timeout to the main loop which
* polls at 100 millisecond intervals and tests is_done()/is_error()
* and is_emitter_done()/is_emitter_error(). The timeout is
* automatically removed by the implementation once it has been
* detected that an error has occurred and the 'fail' callback is
* executed, or if the thread function represented by this Cgu::Future
* object and all done_emitter emissions (including execution of any
* 'when' callback) have completed successfully.
*
* This method can be called before or after the run() method has been
* called, and whether or not the thread function represented by this
* Cgu::Thread::Future object has completed.
*
* Once this method has been called, this Cgu::Thread::Future object
* will always stay in existence until the timeout has been
* automatically removed by the implementation. Accordingly it is
* safe to use this method even if the intrusive pointer object
* returned by the make() methods will go out of scope before the
* 'fail' callback has executed: the callback will execute correctly
* irrespective of that.
*
* This method does not have a priority argument: as a polling timeout
* is created, a particular priority will normally have no
* significance (in fact, the 'fail' callback will execute in the main
* loop with a priority of G_PRIORITY_DEFAULT). If in a special case
* a different polling interval than 100 milliseconds or a different
* priority is required, users can attach their own polling timeouts
* to a main loop and carry out the tests by hand.
*
* Four other points should be noted. First, if as well as the when()
* method being called some other callback has been connected to
* done_emitter, and that other callback throws, the 'fail' callback
* will execute. Therefore, if the particular program design requires
* that the 'fail' callback should only execute if the 'when' callback
* is not executed (and the 'when' callback only execute if the 'fail'
* callback does not execute), no other callbacks which throw should
* be connected to done_emitter.
*
* Secondly, as mentioned in the documentation on the when() method,
* if the 'when' callback exits with an uncaught exception upon being
* executed by the main loop or it represents a function which takes
* an argument by value whose copy constructor throws, the 'fail'
* callback will not execute (the exception will have been consumed
* internally in order to protect the main loop and a g_critical
* message issued).
*
* Thirdly, avoid if possible having a 'fail' callback which might
* throw, or representing a function which takes an argument by value
* whose copy constructor might throw: such an exception would be
* consumed internally in order to protect the main loop and a
* g_critical message issued, but no other error indication apart from
* the g_critical message will be provided.
*
* Fourthly, unlike the 'when' callback, a copy of this
* Cgu::Thread::Future object held by intrusive pointer as returned by
* the make() methods may safely be bound to the 'fail' callback,
* which would enable the 'fail' callback to determine whether it is
* is_error() or is_emitter_error() which returns false.
*
* If glib < 2.32 is used, the glib main loop must have been made
* thread-safe by a call to g_thread_init() before this function is
* called. glib >= 2.32 does not require g_thread_init() to be called
* in order to be thread safe.
*
* @param cb The 'fail' callback (the callback to be executed if the
* thread function represented by this Cgu::Thread::Future object or a
* done_emitter emission has failed to complete). Ownership is taken
* of this object, and it will be deleted when it has been finished
* with.
* @param context The glib main context of the thread in whose main
* loop the 'fail' callback is to be executed (the default of NULL
* will cause the functor to be executed in the main program loop).
* @exception std::bad_alloc This method might throw std::bad_alloc if
* memory is exhausted and the system throws in that case. If it does
* so, the 'fail' callback will be disposed of.
*
* Since 2.0.2
*/
void fail(const Cgu::Callback::Callback* cb,
GMainContext* context = 0);
/**
* This is a version of the fail() utility for use in conjunction with
* the when() methods, which takes a Releaser object for automatic
* disconnection of the callback functor passed as an argument to this
* method if the object having the callback function as a member is
* destroyed. For this to be race free, the lifetime of that object
* must be controlled by the thread in whose main loop the 'fail'
* callback will execute.
*
* This method enables a callback to be executed in a glib main loop
* if memory is exhausted and std::bad_alloc was thrown by the thread
* wrapper of Cgu::Thread::Future after calling run() or by
* done_emitter when emitting, or if the thread function represented
* by this Cgu::Thread::Future object threw Cgu::Thread::Exit, exited
* with an uncaught exception deriving from std::exception or was
* cancelled (or that function took an argument of class type by value
* whose copy constructor threw such an exception or had a return
* value of class type whose move assignment operator, or if none copy
* assignment operator, threw such an exception), or any callback
* connected to done_emitter exited with an uncaught exception. It
* therefore enables errors to be detected and acted on without having
* a thread wait on the get() method in order to test is_error() or
* is_emitter_error().
*
* This method can be called before or after the run() method has been
* called, and whether or not the thread function represented by this
* Cgu::Thread::Future object has completed.
*
* The documentation for the version of this method which does not
* take a Releaser object gives further details of how this method is
* used.
*
* If glib < 2.32 is used, the glib main loop must have been made
* thread-safe by a call to g_thread_init() before this function is
* called. glib >= 2.32 does not require g_thread_init() to be called
* in order to be thread safe.
*
* @param cb The 'fail' callback (the callback to be executed if the
* thread function represented by this Cgu::Thread::Future object or a
* done_emitter emission has failed to complete). Ownership is taken
* of this object, and it will be deleted when it has been finished
* with.
* @param r A Releaser object for automatic disconnection of the
* 'fail' callback before it executes in a main loop (mainly relevant
* if the callback represents a non-static member function of an
* object which may be destroyed before the callback executes).
* @param context The glib main context of the thread in whose main
* loop the 'fail' callback is to be executed (the default of NULL
* will cause the functor to be executed in the main program loop).
* @exception std::bad_alloc This method might throw std::bad_alloc if
* memory is exhausted and the system throws in that case. If it does
* so, the 'fail' callback will be disposed of.
* @exception Cgu::Thread::MutexError This method will throw
* Cgu:Thread::MutexError if initialisation of the mutex in a
* SafeEmitterArg object constructed by Cgu::start_timeout() fails.
* If it does so, the 'fail' callback will be disposed of. (It is
* often not worth checking for this, as it means either memory is
* exhausted or pthread has run out of other resources to create new
* mutexes.)
* @note By virtue of the Releaser object, it is in theory possible
* (if memory is exhausted and the system throws in that case) that an
* internal SafeEmitterArg object will throw std::bad_alloc when
* emitting/executing the 'fail' callback in the glib main loop, with
* the result that the relevant callback will not execute (instead the
* exception will be consumed and a g_critical() warning will be
* issued). This is rarely of any relevance because glib will abort
* the program if it is itself unable to obtain memory from the
* operating system. However, where it is relevant, design the
* program so that it is not necessary to provide a releaser object.
*
* Since 2.0.2
*/
void fail(const Cgu::Callback::Callback* cb,
Cgu::Releaser& r,
GMainContext* context = 0);
/**
* @return true if the function or callable object represented by this
* Cgu::Thread::Future object has finished, either by returning
* normally, by cancellation or by virtue of having thrown
* Cgu::Thread::Exit or some exception derived from std::exception.
* Once this method returns true, then it is guaranteed that the get()
* or move_get() method will not block (except as incidental to any
* contention between threads calling get()). Once this method has
* returned true or get() or move_get() has unblocked, then the result
* of is_error() is definitive. This method is thread safe and may be
* called by any thread. It will not throw.
* @note This method will return true even though any callbacks
* connected to done_emitter are still executing or waiting to
* execute. From version 2.0.2 the is_emitter_done() method will
* indicate when done_emitter callbacks (if any) have also completed.
*/
bool is_done() const;
/**
* @return true if both the function or callable object represented by
* this Cgu::Thread::Future object has finished and any callbacks
* connected to done_emitter have completed. Once this method returns
* true, then the result of is_emitter_error() is definitive. This
* method is thread safe and may be called by any thread. It will not
* throw.
* @note This method will return true automatically if is_error() and
* is_done() return true, because if the function or callable object
* represented by this Cgu::Thread::Future object was cancelled or
* exited with an uncaught exception, done_emitter is never emitted.
* In addition, if this method returns true, then is_done() must also
* return true.
*
* Since 2.0.2
*/
bool is_emitter_done() const;
/**
* @return true if (a) a Cgu::Thread::Exit exception has been thrown
* by the function or callable object represented by this
* Cgu::Thread::Future object (which will have been consumed by this
* Cgu::Thread::Future object), (b) an exception derived from
* std::exception has been thrown on invoking that function or object
* which was not caught by it (which will have been consumed by this
* Cgu::Thread::Future object), (c) any of those exceptions have been
* thrown either by the copy constructor of an argument taken by value
* by that function or object, or by the move assignment operator (or
* if none, copy assignment operator) of the return value of that
* function or object (which will have been consumed by this
* Cgu::Thread::Future object), (d) the worker thread in which that
* function or callable object executes was cancelled in mid-course
* with a call to cancel() or (e) the thread wrapper implementing the
* worker thread in this Cgu::Thread::Future object threw and then
* consumed std::bad_alloc (this is different from the run() method
* throwing std::bad_alloc). In these cases the value obtained by
* get() or move_get() will not be valid (it will be a default
* constructed object of the return type of the function represented
* by this Cgu::Thread::Future object). Otherwise this method returns
* false. The result of this method is definitive once get() or
* move_get() has unblocked or is_done() returns true. This method is
* thread safe and may be called by any thread. It will not throw.
*/
bool is_error() const;
/**
* @return true if an uncaught exception arose in emitting @ref
* DoneEmitterAnchor "done_emitter" when executing callbacks connected
* to it. Otherwise this method returns false. The result of this
* method is definitive once is_emitter_done() returns true. This
* method is thread safe and may be called by any thread. It will not
* throw.
* @note This method will return false automatically if is_error()
* returns true, because if the function or callable object
* represented by this Cgu::Thread::Future object was cancelled or
* exited with an uncaught exception, done_emitter is never emitted.
* It follows that if this method returns true, is_error() must return
* false.
*/
bool is_emitter_error() const;
/**
* A Cgu::SafeEmitter object which is emitted when the function or
* callable object represented by this Cgu::Thread::Future object
* finishes correctly (that is, it is not cancelled and does not throw
* any uncaught exceptions). By itself this emission does not do too
* much as it is emitted (and connected callbacks execute in) the same
* worker thread immediately after the Future function has completed.
* However, any thread can connect a callback object to this
* Cgu::SafeEmitter object and a connected callback can, say, cause
* another callback to be executed in a thread's main loop using
* Cgu::Callback::post(), and from version 2.0.2 when() methods are
* provided which will do this for users automatically. Once the
* run() method has been called, this Cgu::Thread::Future object (and
* so done_emitter) will always stay in existence until the function
* or callable object represented by it has completed (whether
* correctly, by cancellation or by a thrown exception) and any
* callbacks connected to the done_emitter object have completed,
* irrespective of whether the intrusive pointer returned by the
* make() or make_future() functions has gone out of scope.
* @note 1. Cancellation is blocked while the Cgu::SafeEmitter object
* emits and any connected callback executes.
* @note 2. A connected callback can however terminate the worker
* thread by throwing Cgu::Thread::Exit (in which case no subsequent
* callbacks to be executed on that emission will execute either: the
* worker thread will safely terminate and unwind the stack in so
* doing). In that event, the emitter_error flag will be set.
* @note 3. All other uncaught exceptions which might be thrown by the
* Cgu::SafeEmitter object emitting, or by a connected callback
* function executing, are consumed to retain the integrity of the
* Thread::Future object. In the event of such an exception being
* thrown, the emitter_error flag will be set. In summary, the
* emitter_error flag will be set if (a) a connected callback function
* throws Cgu::Thread::Exit, (b) some other uncaught exception escapes
* from a connected callback function or (c) Cgu::SafeEmitter::emit()
* throws std::bad_alloc or the copy constructor of a bound argument
* which is not a reference argument has thrown. If the user knows
* that the callback function does not throw Cgu::Thread::Exit and
* does not allow any other exception to escape, then the cause must
* be a std::bad_alloc memory exception in Cgu::SafeEmitter::emit() or
* the copy constructor of a non-reference bound argument throwing.
* @note 4. An emission is thread safe if the connected callback
* functions are thread safe.
* @note 5. This Cgu::Thread::Future object's mutex is released while
* the Cgu::SafeEmitter object emits. This means that any connected
* callbacks can safely call, say, the Future object's get() or
* is_error() methods. However, a connected callback should not hold
* a bound argument comprising a copy of this Cgu::Thread::Future
* object held by intrusive pointer as returned by the make() or
* make_future() methods (that would result in this
* Cgu::Thread::Future object owning, via done_emitter, a reference to
* itself and so become incapable of being freed). The callback may,
* however, take a pointer to this Cgu::Thread::Future object as a
* bound argument, as obtained by the Cgu::IntrusivePtr::get() method,
* because this Cgu::Thread::Future object is guaranteed to remain in
* existence until all callbacks connected to done_emitter have
* completed executing.
* @anchor DoneEmitterAnchor
*/
SafeEmitter done_emitter;
/* Only has effect if --with-glib-memory-slices-compat or
* --with-glib-memory-slices-no-compat option picked */
CGU_GLIB_MEMORY_SLICES_FUNCS
};
/**
* A convenience helper function which calls
* Cgu::Thread::Future::make() to obtain a Future object without the
* need to specify the return value of the function represented by the
* new object: that is deduced from the signature of that function.
* This is useful shorthand when also employed with the C++11/14
* 'auto' keyword.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type of the function represented by the new object
* throws.
*
* Since 2.0.4
*/
template <class Obj, class Ret, class... Params, class... Args>
Cgu::IntrusivePtr<Cgu::Thread::Future<Ret>> make_future(Obj& obj,
Ret (Obj::*func)(Params...),
Args&&... args) {
return Cgu::Thread::Future<Ret>::make(obj, func, std::forward<Args>(args)...);
}
/**
* A convenience helper function which calls
* Cgu::Thread::Future::make() to obtain a Future object without the
* need to specify the return value of the function represented by the
* new object: that is deduced from the signature of that function.
* This is useful shorthand when also employed with the C++11/14
* 'auto' keyword.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type of the function represented by the new object
* throws.
*
* Since 2.0.4
*/
template <class Obj, class Ret, class... Params, class... Args>
Cgu::IntrusivePtr<Cgu::Thread::Future<Ret>> make_future(const Obj& obj,
Ret (Obj::*func)(Params...) const,
Args&&... args) {
return Cgu::Thread::Future<Ret>::make(obj, func, std::forward<Args>(args)...);
}
/**
* A convenience helper function which calls
* Cgu::Thread::Future::make() to obtain a Future object without the
* need to specify the return value of the function represented by the
* new object: that is deduced from the signature of that function.
* This is useful shorthand when also employed with the C++11/14
* 'auto' keyword.
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note This method will also throw if the copy or move constructor
* of a bound argument throws, or the default constructor of the
* return value type of the function represented by the new object
* throws.
*
* Since 2.0.4
*/
template <class Ret, class... Params, class... Args>
Cgu::IntrusivePtr<Cgu::Thread::Future<Ret>> make_future(Ret (*func)(Params...),
Args&&... args) {
return Cgu::Thread::Future<Ret>::make(func, std::forward<Args>(args)...);
}
/**
* A convenience helper function which calls
* Cgu::Thread::Future::make() to obtain a Future without the need to
* specify the return value of the callable object to be represented
* by it: that is deduced. This is useful shorthand when also
* employed with the C++11/14 'auto' keyword.
*
* From version 2.0.14, this method takes the callable object as a
* template parameter, and in prior versions it took it as a
* std::function object. Before version 2.0.14 it was necessary to
* specify the return value of any callable object which was not a
* std::function object as a specific template parameter: this is not
* necessary in version 2.0.14, as it is deduced automatically.
*
* @param functor The callable object to be executed. It should
* return a value (it cannot return void).
* @exception std::bad_alloc It might throw std::bad_alloc if memory
* is exhausted and the system throws in that case. (This exception
* will not be thrown if the library has been installed using the
* \--with-glib-memory-slices-no-compat configuration option: instead
* glib will terminate the program if it is unable to obtain memory
* from the operating system.)
* @exception Cgu::Thread::MutexError It might throw
* Cgu::Thread::MutexError if initialisation of the contained mutex
* fails. (It is often not worth checking for this, as it means
* either memory is exhausted or pthread has run out of other
* resources to create new mutexes.)
* @exception Cgu::Thread::CondError It might throw
* Cgu::Thread::CondError if initialisation of the contained condition
* variable fails. (It is often not worth checking for this, as it
* means either memory is exhausted or pthread has run out of other
* resources to create new condition variables.)
* @note 1. This method will also throw if the copy or move
* constructor of the callable object passed as an argument throws, or
* the default constructor of the return value type of the function
* represented by the new object throws.
* @note 2. If the callable object passed as an argument has both
* const and non-const operator()() methods, the non-const version
* will be called even if the callable object passed is a const
* object.
*
* Since 2.0.4
*/
// we don't need this version of make_future() for syntactic reasons -
// the version taking a single template parameter will do by itself
// syntactically because it can use decltype. However, we include
// this version in order to be API compatible with c++-gtk-utils <
// 2.0.14, which required the return type to be specified when this
// method is passed something other than a std::function object.
// SFINAE will take care of the rest, except with a corner case where
// all of the following apply: (i) a function object is passed whose
// operator()() method returns a copy of the function object (or
// another function object of the same type), (ii) the function object
// is passed to this method as a rvalue and not a lvalue, and (iii)
// the user specifically states the return type when instantiating
// this template function. This would give rise to an ambiguity, but
// its happening is extremely unlikely, and cannot happen with a
// lambda or the return value of std::bind, because those types are
// only known to the compiler, and cannot happen with other objects if
// the user lets template deduction take its course.
template <class Ret, class Func>
Cgu::IntrusivePtr<Cgu::Thread::Future<Ret>> make_future(Func&& functor) {
return Cgu::Thread::Future<Ret>::make(std::forward<Func>(functor));
}
// we don't want to document this function: it provides the type
// deduction of the return value of the passed functor (it deals with
// cases where this is not specified expressly).
#ifndef DOXYGEN_PARSING
template <class Func>
auto make_future(Func&& functor) -> Cgu::IntrusivePtr<Cgu::Thread::Future<decltype(functor())>> {
// this function will fail to compile if the return type is a
// reference type: that is a feature, not a bug, as a function
// returning a reference lacks referential transparency, is unlikely
// to be thread-safe and is unsuitable for use as a task function
return Cgu::Thread::Future<decltype(functor())>::make(std::forward<Func>(functor));
}
#endif
} // namespace Thread
} // namespace Cgu
#include <c++-gtk-utils/future.tpp>
#endif
Cgu::Thread::Future::is_done
bool is_done() const
Cgu::Thread::FutureWhenError::what
virtual const char * what() const
Definition: future.h:68
Cgu::Callback::CallbackArg
The callback interface class.
Definition: callback.h:522
Cgu
Definition: application.h:44
Cgu::Thread::Future::done_emitter
SafeEmitter done_emitter
Definition: future.h:1587
Cgu::Thread::FutureWhenError
Definition: future.h:67
Cgu::Callback::make
CallbackArg< FreeArgs... > * make(T &t, void(T::*func)(FreeArgs...))
Definition: callback.h:1659
Cgu::Thread::make_future
Cgu::IntrusivePtr< Cgu::Thread::Future< Ret > > make_future(Obj &obj, Ret(Obj::*func)(Params...), Args &&... args)
Definition: future.h:1626
shared_ptr.h
timeout.h
Cgu::Thread::Cond
A wrapper class for pthread condition variables.
Definition: mutex.h:449
Cgu::IntrusivePtr
This is a smart pointer for managing objects allocated on freestore which maintain their own referenc...
Definition: intrusive_ptr.h:98
Cgu::Thread::Future::is_error
bool is_error() const
callback.h
This file provides classes for type erasure.
Cgu::Thread::Future::cancel
bool cancel()
Cgu::Thread::Future::fail
void fail(const Cgu::Callback::Callback *cb, GMainContext *context=0)
intrusive_ptr.h
Cgu::Thread::FutureThreadError
Definition: future.h:63
Cgu::Thread::Future::operator=
Future & operator=(const Future &)=delete
Cgu::SafeEmitterArg
A thread-safe class to execute callbacks connected to it, with provision for automatic disconnection.
Definition: emitter.h:308
Cgu::Thread::Future::move_get
Val move_get()
Cgu::Callback::SafeFunctorArg
Functor class holding a Callback::CallbackArg object, with thread-safe reference count.
Definition: callback.h:726
Cgu::Thread::Future
A class representing a pthread thread which will provide a value.
Definition: future.h:276
Cgu::Thread::Future::is_emitter_error
bool is_emitter_error() const
CGU_GLIB_MEMORY_SLICES_FUNCS
#define CGU_GLIB_MEMORY_SLICES_FUNCS
Definition: cgu_config.h:84
Cgu::IntrusiveLockCounter
This is a counter class providing the ref() and unref() functions required by IntrusivePtr,...
Definition: intrusive_ptr.h:349
mutex.h
Provides wrapper classes for pthread mutexes and condition variables, and scoped locking classes for ...
Cgu::Thread::Future::run
bool run()
Cgu::Thread::Future::when
Cgu::Callback::SafeFunctor when(const Cgu::Callback::CallbackArg< const Val & > *cb, gint priority=G_PRIORITY_DEFAULT, GMainContext *context=0)
Cgu::Releaser
A class used for tracking EmitterArg and SafeEmitterArg connections.
Definition: emitter.h:333
Cgu::Thread::Future::is_emitter_done
bool is_emitter_done() const
Cgu::Thread::Future::get
Val get()
thread.h
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
Cgu::Thread::Thread
A class representing a pthread thread.
Definition: thread.h:166
Cgu::Thread::FutureThreadError::what
virtual const char * what() const
Definition: future.h:64
Cgu::Thread::Future::make
static Cgu::IntrusivePtr< Cgu::Thread::Future< Val > > make(T &t, Ret(T::*func)())
cgu_config.h