In many cases I have classes that act like active objects (have a thread). And to avoid access violations I always have to wait for join in the destructor. Which is usually not a problem.
However imagine a release build with some bug (deadlock, livelock etc.) that causes join()
not to return on time or at all, this would cause the entire application to become non functional while waiting for an object that will not be used again. If this happens at a customer it becomes a problem.
I would rather be notified by the problem and skip the join. And leak the thread and it's resources.
Skipping the join could be achieved through something like this.
class MyActiveObject
{
public:
MyActiveObject();
~MyActiveObject(){}
private
struct Implementation;
std::shared_ptr<Implementation> pImpl_;
};
struct MyActiveObject::Implementation : std::enable_shared_from_this<Implementation >
{
Implementation() : thread_([=]{Run();})
{
}
~Implementation()
{
#ifdef _DEBUG
thread_.join();
#else
if(!thread_.timed_join(SOME_TIMEOUT))
ALERT_SOME_HOW();
#endif
}
void Dispose()
{
isRunning_ = false;
}
void Run()
{
#ifndef _DEBUG
auto pKeepAlive = shared_from_this(); // Won't be destroyed until thread finishes
#endif
isRunning_ = true;
while(isRunning_)
{
/* ... */
}
}
boost::thread thread_;
tbb::atomic<bool> isRunning_;
};
MyActiveObject::MyActiveObject() : pImpl_(new Implementation()){}
MyActiveObject::~MyActiveObject() { pImpl_->Dispose(); }
Is this a good idea? Or are there better strategies?