c++-gtk-utils
|
A class wrapping a Thread::Thread object representing a joinable thread. More...
#include <c++-gtk-utils/thread.h>
Public Types | |
enum | Action { detach_on_exit, join_on_exit } |
Public Member Functions | |
void | cancel () |
bool | join () |
void | detach () |
bool | is_caller () |
bool | is_managing () |
JoinableHandle & | operator= (JoinableHandle &&h) |
JoinableHandle (std::unique_ptr< Cgu::Thread::Thread > thr, Action act) | |
JoinableHandle (JoinableHandle &&h) | |
JoinableHandle () | |
~JoinableHandle () | |
A class wrapping a Thread::Thread object representing a joinable thread.
This class enables a joinable thread to be made more easily exception safe. It can also be used to provide that a joinable thread is not detached or joined while other methods dependent on that might still be called, and to provide a defined result where there are multiple calls to join() and/or detach(). When it is destroyed, it will either detach or join the thread represented by the wrapped Thread::Thread object unless it has previously been detached or joined using the detach() or join() methods, so avoiding thread resource leaks. Whether it will detach() or join() on destruction depends on the Thread::JoinableHandle::Action argument passed to the Thread::JoinableHandle::JoinableHandle(std::unique_ptr<Thread::Thread>, Action) constructor.
Passing Thread::JoinableHandle::detach_on_exit to that argument is not always the correct choice where the thread callback has been bound to a reference argument in local scope and an exception might be thrown, because the thread will keep running after the Thread::JoinableHandle object and other local variables have (because of the exception) gone out of scope. Consider the following trivial parallelized calculation example:
If get_std_deviation() throws, as well as there being a potential thread resource leak by virtue of no join being made, the thread executing get_mean() will continue running and attempt to access variable v, and put its result in variable i, which may by then both be out of scope. To deal with such a case, the thread could be wrapped in a Thread::JoinableHandle object which joins on exit rather than detaches, for example:
Better still, however, would be to use Cgu::Thread::Future in this kind of usage, namely a usage where a worker thread is intended to provide a result for inspection.
|
inline |
This constructor initializes a new JoinableHandle object with a std::unique_ptr<Thread::Thread> object, as provided by Thread::Thread::start(). This is a move operation which transfers ownership to the new object.
thr | The initializing Thread::Thread object (which must have been created as joinable) passed by a std::unique_ptr smart pointer. This is a move operation. |
act | Either Thread::JoinableHandle::detach_on_exit (which will cause the destructor to detach the thread if it has not previously been detached or joined) or Thread::JoinableHandle::join_on_exit (which will cause the destructor to join the thread if it has not previously been detached or joined). |
Cgu::Thread::MutexError | Throws this exception if initialization of the internal mutex fails. The constructor is strongly exception safe: if Cgu::Thread::MutexError is thrown, the initializing std::unique_ptr<Cgu::Thread::Thread> object will be left unchanged. (It is often not worth checking for this exception, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.) |
|
inline |
This constructor initializes a new JoinableHandle object with an existing JoinableHandle object. This is a move operation which transfers ownership to the new object.
h | The initializing JoinableHandle object, which will cease to hold a valid Thread::Thread object after the initialization has taken place. |
Cgu::Thread::MutexError | Throws this exception if initialization of the internal mutex fails. The constructor is strongly exception safe: if Cgu::Thread::MutexError is thrown, the initializing Cgu::Thread::JoinableHandle object will be left unchanged. (It is often not worth checking for this exception, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.) |
|
inline |
The default constructor. Nothing is managed until the move assignment operator has been called.
Cgu::Thread::MutexError | Throws this exception if initialization of the internal mutex fails. (It is often not worth checking for this exception, as it means either memory is exhausted or pthread has run out of other resources to create new mutexes.) |
Since 2.0.8
Cgu::Thread::JoinableHandle::~JoinableHandle | ( | ) |
The destructor will detach a managed thread (if the Thread::JoinableHandle::detach_on_exit flag is set) or join it (if the Thread::JoinableHandle::join_on_exit flag is set), unless it has previously been detached or joined with the detach() or join() methods. The destructor is thread safe (any thread may destroy the JoinableHandle object). The destructor will not throw.
void Cgu::Thread::JoinableHandle::cancel | ( | ) |
Cancels the thread represented by the wrapped Thread::Thread object. It can be called by any thread. The effect is undefined if when called the thread represented by the wrapped Thread::Thread object has both (a) already terminated and (b) had a call to join() or detach() made for it. Accordingly, if the user is not able to establish from the program logic whether the thread has terminated, cancel() must not be called after a call to detach() has been made or a call to join() has returned: this can be ensured by only detaching or joining via this object's destructor (that is, by not using the explicit detach() and join() methods). This method does not throw.
void Cgu::Thread::JoinableHandle::detach | ( | ) |
Detaches the thread represented by this Thread::Thread object, so as to make it unjoinable, unless the detach() or join() method has previously been called in which case this call does nothing. It does not throw.
bool Cgu::Thread::JoinableHandle::is_caller | ( | ) |
Specifies whether the calling thread is the same thread as is represented by the wrapped Thread::Thread object. It can be called by any thread. The effect is undefined if the thread represented by the wrapped Thread::Thread object has both (a) already terminated and (b) had a call to join() or detach() made for it. Accordingly, if the user is not able to establish from the program logic whether the thread has terminated, is_caller() must not be called after a call to detach() has been made or a call to join() has returned: this can be ensured by only detaching or joining via this object's destructor (that is, by not using the explicit detach() and join() methods). This method does not throw.
bool Cgu::Thread::JoinableHandle::is_managing | ( | ) |
Specifies whether this JoinableHandle object has been initialized with a Thread::Thread object representing a correctly started thread in respect of which neither JoinableHandle::detach() nor JoinableHandle::join() has been called. It can be called by any thread. It is principally intended to enable the constructor taking a std::unique_ptr<Cgu::Thread::Thread> object to be directly initialized by a call to Thread::Thread::start(), by providing a means for the thread calling Thread::Thread::start() to check afterwards that the new thread did, in fact, start correctly. Note that this method will return true even after the thread has finished, provided neither the join() nor detach() method has been called.
bool Cgu::Thread::JoinableHandle::join | ( | ) |
Joins the thread represented by the wrapped Thread::Thread object (that is, waits for it to terminate), unless the detach() or join() method has previously been called in which case this call does nothing. It can be called by any thread other than the one represented by the wrapped Thread::Thread object, but only one thread can wait on it: if one thread (thread A) calls it while another thread (thread B) is already blocking on it, thread A's call to this method will return immediately and return false. It does not throw.
JoinableHandle& Cgu::Thread::JoinableHandle::operator= | ( | JoinableHandle && | h | ) |
Moves one JoinableHandle object to another JoinableHandle object. This is a move operation which transfers ownership to the assignee, as the handles store their Thread::Thread object by std::unique_ptr<>. Any existing thread managed by the assignee prior to the move will be detached if it has not already been detached or joined. This method will not throw.
h | The assignor/movant, which will cease to hold a valid Thread::Thread object after the move has taken place. |