c++-gtk-utils
Public Member Functions | Static Public Member Functions
Cgu::Thread::Thread Class Reference

A class representing a pthread thread. More...

#include <c++-gtk-utils/thread.h>

List of all members.

Public Member Functions

 Thread (const Thread &)
Threadoperator= (const Thread &)
void cancel ()
void join ()
void detach ()
bool is_caller ()

Static Public Member Functions

static std::unique_ptr
< Cgu::Thread::Thread
start (const Cgu::Callback::Callback *cb, bool joinable)

Detailed Description

A class representing a pthread thread.

See also:
Thread::Mutex Thread::Mutex::Lock Thread::Cond Thread::Future Thread::JoinableHandle

The Thread class encapsulates a pthread thread. It can start, join and cancel a thread.

The Thread class, and the associated CancelBlock class, can be used interchangeably with (and mixed with) GThread objects and functions, and GMutex, GStaticMutex, GStaticRecMutex and GCond, as they all use pthreads underneath on POSIX and other unix-like OSes. In addition it can be used with threads started with the C++11 threading facilities, as in C++11 on unix-like OSes these facilities will be built on top of pthreads (for which purpose C++11 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.

c++-gtk-utils library and C++11 threads

As mentioned above, the thread facilities provided by this library can be freely interchanged with the threading facilities provided by C++11.

The main features available from this library and not C++11 are thread cancellation and the associated Cgu::Thread::CancelBlock class, and the Cgu::Thread::JoinableHandle class for scoped joinable thread handling.

C++11 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.* 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 some 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 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: a guaranteed monotonic clock on timed condition variable waits where the operating system supports them; read-write locks; and a Cgu::Thread::Future object which is more intuitive to use than C++11 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.

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 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.


Constructor & Destructor Documentation

Cgu::Thread::Thread::Thread ( const Thread )

This class cannot be copied: it is intended to be held by std::unique_ptr. The copy constructor is deleted.


Member Function Documentation

void Cgu::Thread::Thread::cancel ( )
inline

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.

Note:
Use this method with care - sometimes its use is unavoidable but destructors for local objects may not be called if a thread exits by virtue of a call to cancel() (that depends on the implementation). Most modern commercial unixes, and recent linux/BSD distributions based on NPTL, 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 only have 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 implement some clean-ups with pthread_cleanup_push()/pthread_cleanup_pop(). This should be controlled with pthread_setcancelstate() and/or the CancelBlock class to choose the cancellation point.
See also:
Cgu::Thread::Exit
void Cgu::Thread::Thread::detach ( )
inline

Detaches the thread represented by this Thread object where it is joinable, so as to make it unjoinable. The effect is unspecified 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.

bool Cgu::Thread::Thread::is_caller ( )
inline

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.

Returns:
Returns true if the caller is in the thread represented by this Thread object.
void Cgu::Thread::Thread::join ( )
inline

Joins the thread represented by this Thread object (that is, waits for it to terminate). It can be called by any thread other than the one represented by this Thread object. The result is undefined if the thread is or was detached or join() has already been called for the thread (a Thread::JoinableHandle object will however give a defined result in such cases for threads originally started as joinable). It does not throw.

Thread& Cgu::Thread::Thread::operator= ( const Thread )

This class cannot be copied: it is intended to be held by std::unique_ptr. The assignment operator is deleted.

static std::unique_ptr<Cgu::Thread::Thread> Cgu::Thread::Thread::start ( const Cgu::Callback::Callback cb,
bool  joinable 
)
static

Starts a new thread. It can be called by any thread.

Parameters:
cbA callback object (created by Callback::make()) 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).
joinableWhether the join() method may be called in relation to the new thread.
Returns:
A Thread object representing the new thread which has been started, held by a std::unique_ptr object as it has single ownership semantics. The std::unique_ptr object will be empty (that is std::unique_ptr<Cgu::Thread::Thread>::get() will return 0) if the thread did not start correctly, which would mean that memory is exhausted, the pthread thread limit has been reached or pthread has run out of other resources to start new threads.
Exceptions:
std::bad_allocThis 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.)
Note:
1. The thread will keep running even if the return value of start() goes out of scope (but it will no longer be possible to call any of the methods in this class for it, which is fine if the thread is not started as joinable and it is not intended to cancel it).
2. If the thread is started with the joinable attribute, the user must subsequently either call the join() or the detach() method, as otherwise a resource leak may occur (the destructor of this class does not call detach() automatically). Alternatively, the return value of this method can be passed to a Thread::JoinableHandle object which will do this automatically in the Thread::JoinableHandle object's destructor.
3. Any Thread::Exit exception thrown from the function executed by the new thread will be caught and consumed. The thread will safely terminate and unwind the stack in so doing.
4. If any uncaught exception other than Thread::Exit is allowed to propagate from the initial function executed by the new thread, the exception is not consumed (NPTL's forced stack unwinding on cancellation does not permit catching with an ellipsis argument without rethrowing, and even if it did permit it, the result would be an unreported error). The C++11 standard requires std::terminate() to be called in such a case and so the entire program terminated. Accordingly, a user must make sure that no exceptions, other than Thread::Exit or any cancellation pseudo-exception, can propagate from the initial function executed by the new thread.
5. If the library is compiled using the –with-auto-ptr configuration option, then this function will return a Thread::Thread object by std::auto_ptr instead of std::unique_ptr in order to retain compatibility with the 1.2 series of the library.

The documentation for this class was generated from the following file: