randolf.ca
1.00
Randolf Richardson's C++ classes
|
This rthread thread library provides an easier and sufficiently-complete object-oriented thread interface class for C++ that adds a properly-honoured destructor, and without terminating the entire application when the thread throws an exception. This class also provides a virtual method for optionally handling all exceptions (that are otherwise ignored by default) in a penultimate stage prior to commencing onward to the final destructor stage. More...
#include <randolf/rthread>
Public Member Functions | |
rthread () noexcept | |
Default constructor. You can subclass this constructor and/or create parameterized constructors, any of which may throw exceptions (even though this default one doesn't). | |
virtual | ~rthread () noexcept |
Default destructor. Called only after two conditions are met: | |
virtual void | _rthread_exceptions (const std::exception *e) noexcept |
Final rthread exception handler. If an uncaught exception is thrown from the run() method in a running rthread, then it will be handled by this method (which is still technically running on the underlying pthread). Override this method to handle known and unknown exceptions gracefully, which will run before the destructor (or reinitiator) runs. | |
virtual void | _rthread_reinitialize () noexcept |
Re-initialize internal variables, refresh resources, etc., before re-running a reuseable rthread. When utilizing the reuseable feature, this method can be thought of as having similar functionality to that of the constructor, except that it is used to do the following to bring internal variables and resources back to the same state that the constructor originally initialized them to, and thus reducing construction overhead (some variables may not need re-initializing, which can also help to further-reduce overhead): | |
rthread & | detach () |
Daemonize this rthread. | |
bool | detached () noexcept |
Find out whether this rthread is daemonized. | |
rthread & | join () |
Join this rthread to the current thread that called this method. (This is how non-daemonized threads are normally terminated.) | |
pthread_t | pthread_id () noexcept |
Find out what the underlying pthread_id is. | |
bool | reuseable () noexcept |
Find out whether this rthread can be re-used. | |
rthread & | reuseable (bool flag) noexcept |
Configure whether this rthread can be re-used. | |
virtual void | run ()=0 |
Thread functionality (subclassing this method is required). | |
ulong | run_count () noexcept |
Find out how many times this rthread was started. This method is only really meaningful for reuseable rthreads. | |
bool | running () noexcept |
Find out whether this rthread is actively running. | |
rthread & | start () |
Commence execution of the run() method as a separate rthread. | |
rthread & | start_detached () |
Commence execution of the run() method as a separate thread in a daemonized state. | |
rthread & | stop () noexcept |
Request the graceful termination of this rthread. | |
This rthread thread library provides an easier and sufficiently-complete object-oriented thread interface class for C++ that adds a properly-honoured destructor, and without terminating the entire application when the thread throws an exception. This class also provides a virtual method for optionally handling all exceptions (that are otherwise ignored by default) in a penultimate stage prior to commencing onward to the final destructor stage.
POSIX threads are the foundation of the rthread class, and the resulting C++ interface will probably seem familiar to those who are familliar with Java.
Some advanced features are planned that exceed what the basic thread functions provide, but are also needed:
After looking for existing solutions (none of which resolved the ineherent problems with threads in C++), I embarked on creating this rthread class, which was highly educational but also wasn't difficult. The end result is a small class that's easy to maintain, eliminates the reliability concerns, and is easy to use primarily because C++ thoroughly supports subclassing.
My background in programming began when I was a young child, teaching myself BASIC and then machine language (when I found BASIC to be too limited) before moving on to other languages like Perl and Java many years later. Eventually I circled around to C (which I chose to learn the hard way by writing some PostgreSQL extensions) and then C++ a few years after that. I have a lot of experience with programming threadded applications on a variety of platforms that support pthreads (including Novell's NetWare), running application code I created that ran hundreds of thousands of threads successfully serving a similar number of users globally without slowdowns or crashes.
|
inlinenoexcept |
Default constructor. You can subclass this constructor and/or create parameterized constructors, any of which may throw exceptions (even though this default one doesn't).
This is particularly useful for performing pre-run setup before starting the thread (see the run() and start() methods for details), especially with threads that start running in response to external events (such as user interaction events, incoming internet socket connections, etc.).
|
inlinevirtualnoexcept |
Default destructor. Called only after two conditions are met:
Exceptions are handled by the _rthread_exceptions() method before this destructor is activated.
You can add your own destructor to safely ensure that files and sockets are closed, and that resources are freed, deallocated, deleted, etc., which is essential to preventing various types of resource leaks if your thread code (in the run() method) exited early due to an unexpected exception (it is the developer's responsibility to ensure resources are managed properly, and this destructor provides a means of handling this reliably).
Logging, re-queuing, semaphore completions, etc., can also be handled in this method because it runs after the termination of the underlying pthread.
std::exception
.
|
inlinevirtualnoexcept |
Final rthread exception handler. If an uncaught exception is thrown from the run() method in a running rthread, then it will be handled by this method (which is still technically running on the underlying pthread). Override this method to handle known and unknown exceptions gracefully, which will run before the destructor (or reinitiator) runs.
e
is nullptr
it means an unknown exception was thrown (e.g., internally we literally caught (...)
(other exception), in which case you'll need to use std::current_exception()
to access it. e | Exceptions (see warning, immediately above) |
|
inlinevirtualnoexcept |
Re-initialize internal variables, refresh resources, etc., before re-running a reuseable rthread. When utilizing the reuseable feature, this method can be thought of as having similar functionality to that of the constructor, except that it is used to do the following to bring internal variables and resources back to the same state that the constructor originally initialized them to, and thus reducing construction overhead (some variables may not need re-initializing, which can also help to further-reduce overhead):
this
to a thread pool or concurrent queue of ready rthreads
|
inline |
Daemonize this rthread.
If this rthread was previously detached, then this method has no effect (but won't cause the randolf::rex::xEINVAL exception to be thrown; there may be other reasons for this exception to be thrown).
randolf::rex::xEINVAL | Not a joinable rthread |
randolf::rex::xESRCH | A pthread with the underlying pthread_id couldn't be found (underlying pthread doesn't exist) |
|
inlinenoexcept |
Find out whether this rthread is daemonized.
|
inline |
Join this rthread to the current thread that called this method. (This is how non-daemonized threads are normally terminated.)
randolf::rex::xEDEADLK | Deadlock detected because two threads are queued to join with each other, or the current rthread is trying to join with itself |
randolf::rex::xEINVAL | Not a joinable rthread |
randolf::rex::xEINVAL | A different thread is already queued to join with this rthread |
randolf::rex::xESRCH | A pthread with the underlying pthread_id couldn't be found (underlying pthread doesn't exist) |
|
inlinenoexcept |
Find out what the underlying pthread_id
is.
Advanced developers may want easy access to this ID for a variety of reasons.
|
inlinenoexcept |
Find out whether this rthread can be re-used.
|
inlinenoexcept |
Configure whether this rthread can be re-used.
flag | TRUE = Set this rthread to be re-useable FALSE = Set this rthread to not be re-useable |
|
pure virtual |
Thread functionality (subclassing this method is required).
|
inlinenoexcept |
Find out how many times this rthread was started. This method is only really meaningful for reuseable rthreads.
|
inlinenoexcept |
|
inline |
Commence execution of the run()
method as a separate rthread.
randolf::rex::xEWOULDBLOCK | (xEAGAIN) Insufficient resources to start the underlying pthread |
randolf::rex::xEWOULDBLOCK | (xEAGAIN) Maximum number-of-threads limit reached |
|
inline |
Commence execution of the run()
method as a separate thread in a daemonized state.
randolf::rex::xEDEADLK | Deadlock detected because two threads are queued to join with each other, or the current rthread is trying to join with itself |
randolf::rex::xEINVAL | Not a joinable rthread |
randolf::rex::xEINVAL | A different thread is already queued to join with this rthread |
randolf::rex::xENOMEM | Insufficient memory (on Linux this normally always succeeds, but there's not guarantee as the community suggests that this could change in the future) |
randolf::rex::xESRCH | A pthread with the underlying pthread_id couldn't be found (underlying pthread doesn't exist) |
|
inlinenoexcept |
Request the graceful termination of this rthread.
randolf::rex::xEINVAL | Not a joinable rthread |
randolf::rex::xESRCH | A pthread with the underlying pthread_id couldn't be found (underlying pthread doesn't exist) |