c++-gtk-utils
|
A class representing a pthread thread. More...
#include <c++-gtk-utils/thread.h>
Public Member Functions | |
Thread (const Thread &)=delete | |
Thread & | operator= (const Thread &)=delete |
void | cancel () noexcept |
void | join () noexcept |
void | detach () noexcept |
bool | is_caller () noexcept |
Static Public Member Functions | |
static std::unique_ptr< Cgu::Thread::Thread > | start (const Cgu::Callback::Callback *cb, bool joinable) |
template<class F , class = typename std::enable_if<!std::is_convertible<typename std::remove_reference<F>::type, const Cgu::Callback::Callback*>::value>::type> | |
static std::unique_ptr< Cgu::Thread::Thread > | start (F &&func, bool joinable) |
A class representing a pthread thread.
The Thread class encapsulates a pthread thread. It can start, join and cancel a thread.
The Thread class, and the other thread related classes provided by this library such as Mutex, RecMutex, RWLock, CancelBlock and Cond, can be used interchangeably with (and mixed with) GThread objects and functions, and with GMutex, GRecMutex, GRWLock, GCond and similar, as they all use pthreads underneath on POSIX and other unix-like OSes.
In addition, the thread related classes provided by this library can be used in conjunction with threads started with C++11/14 threading facilities, and vice versa, as in C++11/14 on unix-like OSes these facilities are likely to be built on top of pthreads (for which purpose C++11/14 provides the std::native_handle_type type and std::thread::native_handle() function). Even where they are not, they will use the same threading primitives provided by the kernel: ยง30.3 of the C++11 standard states, albeit non-normatively, that "These threads [std::thread threads] are intended to map one-to-one with operating system threads".
If in doubt, always use this library's thread related classes as they are guaranteed to be compatible with glib/gtk and with the native platform libraries. However, such doubts are in practice unnecessary: it is in practice inconceivable that C++11/14's threading implementation will be incompatible with the platform's native threading implementation (pthreads), because any practical program using C++11/14 threads is going to call into platform libraries, and those libraries may themselves be threaded or make thread related calls. So use whichever appears to suit the particular case better.
c++-gtk-utils library and C++11/14 threads
As mentioned above, the thread facilities provided by this library can be freely interchanged with the threading facilities provided by C++11/14.
The main features available from this library and not C++11/14 are thread cancellation and the associated Cgu::Thread::CancelBlock class, the Cgu::Thread::JoinableHandle class for scoped joinable thread handling and the Cgu::Thread::TaskManager class for running and composing tasks on a thread pool.
C++11/14 does not provide thread cancellation or interruption support, and C++ will never be able to do so on a complete basis because to do so requires support from the underlying OS, which therefore makes it platform specific (in this case, POSIX specific): cancellation is only of limited use if it cannot reliably interrupt blocking system calls. The POSIX specification sets out the interruptible cancellation points in System Interfaces, section 2.9.5, Cancellation Points, and in effect specifies all the system calls which can block as cancellation points.
Whether, in C++ programs, destructors of local objects in the cancelled thread are called is also system specific and is not specified by POSIX. Most modern commercial unixes, and recent linux/BSD distributions based on NPTL (in the case of Linux, those based on 2.6/3.x/4.x kernels), will unwind the stack and call destructors on thread cancellation by means of a pseudo-exception, but older distributions relying on the former linuxthreads implementation will not. Therefore for maximum portability cancellation would only be used where there are plain data structures/built-in types in existence in local scope when it occurs, and if there is anything in free store to be released clean-ups would be implemented with pthread_cleanup_push()/pthread_cleanup_pop(). This should be controlled with pthread_setcancelstate() and/or the CancelBlock class to choose the cancellation point.
One of the (perhaps odd) features of C++11/14 threads is that if the destructor of a std::thread object is called which represents a joinable thread which has not been detach()ed or join()ed, the whole program is terminated with a call to std::terminate(), which makes it difficult to use in the presence of exceptions. Often what is wanted however is for join() to be called on a joinable thread where the associated thread object goes out of scope, or (provided it is done carefully and knowingly) for detach() to be called. The Cgu::Thread::JoinableHandle class can be used where either of these two is the appropriate response to this situation.
In addition, the c++-gtk-utils library provides the following which are not present in C++11 and/or C++14: a guaranteed monotonic clock on timed condition variable waits where the operating system supports them; read-write locks/shared mutexes (present in C++14 but not C++11); a Cgu::Thread::Future object which is more intuitive to use than C++11/14 futures and features a built in Cgu::SafeEmitter object which emits when the particular task has completed, and (since version 2.0.2) has associated Cgu::Thread::Future::when() methods for passing the result to a glib main loop; and (since version 2.2.2) Cgu::Thread::parallel_for_each() and Cgu::Thread::parallel_transform() functions for use with Cgu::Thread::TaskManager objects.
c++-gtk-utils library and gthreads
As mentioned above, the thread facilities provided by this library can be freely interchanged with the threading facilities provided by glib.
The main features available with this thread implementation and not GThreads are thread cancellation, the mutex scoped locking classes Cgu::Thread::Mutex::Lock and Cgu::Thread::RecMutex::Lock, the joinable thread scoped management class Cgu::Thread::JoinableHandle and the Cgu::Thread::Future class (abstracting thread functions which provide a result).
There is no need from the perspective of this class to call g_thread_init() before Cgu::Thread::Thread::start() is called, but prior to glib version 2.32 glib itself is not thread-safe without g_thread_init(), so where this class is used with glib < 2.32, g_thread_init() should be called at program initialization.
See Writing multi-threaded programs using c++-gtk-utils for particulars about GTK+ thread safety.
|
delete |
This class cannot be copied: it is intended to be held by std::unique_ptr. The copy constructor is deleted.
|
inlinenoexcept |
Cancels the thread represented by this Thread object. It can be called by any thread. The effect is undefined if the thread represented by this Thread object has both (a) already terminated and (b) been detached or had a call to join() made for it. Accordingly, if the user is not able to establish from the program logic whether the thread has terminated, the thread must be created as joinable and cancel() must not be called after a call to detach() has been made or a call to join() has returned. A Thread::JoinableHandle object can used to ensure this. It does not throw.
|
inlinenoexcept |
Detaches the thread represented by this Thread object where it is joinable, so as to make it unjoinable. The effect is undefined if the thread is already unjoinable (a Thread::JoinableHandle object will however give a defined result in such cases for threads originally started as joinable). It does not throw.
|
inlinenoexcept |
Specifies whether the calling thread is the same thread as is represented by this Thread object. The effect is undefined if the thread represented by this Thread object has both (a) already terminated and (b) been detached or had a call to join() made for it. Accordingly, if the user is not able to establish from the program logic whether the thread has terminated, the thread must be created as joinable and is_caller() must not be called after a call to detach() has been made or a call to join() has returned. A Thread::JoinableHandle object can used to ensure this. This method does not throw.
|
inlinenoexcept |
Joins the thread represented by this Thread object (that is, waits for it to terminate). It can only be called by one thread, which can be any thread other than the one represented by this Thread object. The result is undefined if the thread represented by this Thread object is or was detached or join() has already been called for it (a Thread::JoinableHandle object will however give a defined result in such cases for threads originally started as joinable). It does not throw.
This class cannot be copied: it is intended to be held by std::unique_ptr. The assignment operator is deleted.
|
static |
Starts a new thread. It can be called by any thread.
cb | A callback object (created by Callback::make(), Callback::make_ref() or Callback::lambda()) encapsulating the function to be executed by the new thread. The Thread object returned by this function will take ownership of the callback: it will automatically be deleted either by the new thread when it has finished with it, or by this method in the calling thread if the attempt to start a new thread fails (including if std::bad_alloc is thrown). |
joinable | Whether the join() method may be called in relation to the new thread. |
std::bad_alloc | This method 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.) If this exception is thrown, the thread will not have started. |
|
inlinestatic |
Starts a new thread. It can be called by any thread.
func | A callable object, such as formed by a lambda expression or the result of std::bind, which will be executed by the new thread. |
joinable | Whether the join() method may be called in relation to the new thread. |
std::bad_alloc | This method 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.) If this exception is thrown, the thread will not have started. |
Since 2.1.0