Inconsistent behaviour when calling join() in the destructor - c++

Considering the following code, where I declare a simple class for executing asynchronous/threaded operations:
#include <chrono>
#include <thread>
#include <mutex>
#include <future>
#include <iostream>
using namespace std::chrono_literals;
class basic_executor {
public:
basic_executor() {
_mx.lock();
printf("Ctor #%p\n", this);
_mx.unlock();
}
virtual ~basic_executor() {
_mx.lock();
printf("Dtor #%p\n", this);
_mx.unlock();
if (_thread.joinable()) {
_thread.join();
_mx.lock();
printf("Joined thread #%p\n", this);
_mx.unlock();
}
}
// sync call
void run() {
start();
execute();
stop();
}
// async call
void launch(bool detach = false) {
// create packaged task
std::packaged_task< void() > task([this] {
start();
execute();
stop();
});
// assign future object to function return
_done = task.get_future();
// launch function on a separate thread
_thread = std::thread(std::move(task));
// detach them from main thread in order to avoid waiting for them
if (detach == true) {
_thread.detach();
}
}
// blocking wait for async (detached/joinable)
void wait() const {
_done.wait();
}
protected:
virtual void start() { /* for derived types to implement */ }
virtual void stop() { /* for derived types to implement */ }
virtual void execute() { /* for derived types to implement */ }
std::mutex _mx;
std::thread _thread;
std::future< void > _done;
};
And using the following application example where I derive from it to create two logger objects that make dummy prints for a certain span of time:
class logger : public basic_executor {
public:
logger() { /* ... */}
~logger() {
_mx.lock();
std::cout << "logger destructor " << std::endl;
_mx.unlock();
}
void execute() override {
std::this_thread::sleep_for(1s);
for (int i = 0; i < 10; ++i) {
_mx.lock();
printf("L1: I am printing something\n");
_mx.unlock();
std::this_thread::sleep_for(1s);
}
}
void stop() override {
_mx.lock();
printf("L1: I am done!\n");
_mx.unlock();
}
};
class logger2 : public basic_executor {
public:
logger2() { /* ... */}
~logger2() {
_mx.lock();
printf("logger2 destructor\n");
_mx.unlock();
}
void execute() override {
for (int i = 0; i < 10; ++i) {
_mx.lock();
printf("L2: I am ALSO printing something\n");
_mx.unlock();
std::this_thread::sleep_for(2s);
}
}
void stop() override {
_mx.lock();
printf("L2: I am done!\n");
_mx.unlock();
}
};
int main(int argc, char const *argv[]) {
/* code */
// printf("log:\n");
logger log1;
// printf("log1:\n");
logger2 log2;
printf("----------------------------------!\n");
log2.launch();
log1.launch();
// log1.wait();
// log2.wait();
printf("----------------------------------!\n");
return 0;
}
I am getting an unexpected behavior from the program:
Ctor #0x7fff8b18c990
Ctor #0x7fff8b18c9e0
----------------------------------!
----------------------------------!
logger2 destructor
Dtor #0x7fff8b18c9e0
Joined thread #0x7fff8b18c9e0
logger destructor
Dtor #0x7fff8b18c990
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
L1: I am printing something
Joined thread #0x7fff8b18c990
in that occasionally, the 'log2' object never starts its execution before being destroyed, or the 'join()' call on its destructor hangs indefinitely. Is there any obvious reason why this happens, what exactly am I missing here?

The bug can occur with either logging class. However, with undefined behavior you have no guarantees whatsoever, and no expectation of any kind of consistent results. You've only, so far, observed the same bug with one of two logging classes. Although I can explain why is that, in practical terms, it is immaterial. The bug can happen with either of the objects. Let's begin here:
_thread = std::thread(std::move(task));
You are not going to get any guarantees whatsoever that the new execution thread will immediately start executing any of the following before this code proceeds and returns from launch():
std::packaged_task< void() > task([this] {
start();
execute();
stop();
});
Most of the time, practically, this is going to start running pretty quickly, in the new execution thread. But you cannot rely on that. All that C++ guarantees you is that at some point after std::thread finishes constructing a new execution thread will start running. It may be immediate. Or, it may be a few hundred milliseconds later because your operating system had something more important on its plate.
You are expecting that the new execution thread will always start executing "immediately", simultaneous with std::thread getting constructed. That is not true. After all, you might be running with a single CPU core, and after constructing the std::thread object you're continuing to execute what follows in the same execution thread, and only a while later a context switch occurs, to the new execution thread.
Meanwhile:
launch() returns.
The parent execution thread reaches the end of main().
All of the objects in the automatic scope are going to get destroyed, one by one.
In C++, when an object consists of a superclass and a subclass, the subclass gets destroyed first, followed by the superclass. This is how C++ works.
So, the logger/logger2 subclass's destructor gets immediately invoked and it destroys the its object (just the logger/logger2 subclass).
Now the superclass's destructor gets invoked, to destroy the superclass. ~basic_executor starts doing its thing, patiently waiting.
And now, finally, that new execution thread, remember that one? Guess what: it finally starts running, and valiantly tries to execute start(), execute(), and stop(). Or maybe it managed to get through start(), first, but hasn't reached execute() yet. But since the actual logger subclass is already destroyed now, guess what happens? Nothing. It's gone. The subclass is no more. It ceased to be. It joined the choir invisible. It is pining for the fjords. It's an ex-subclass. There is no logger::execute or logger2::execute() any more.

Related

Pure virtual call from another thread using shared pointer

I am finding it very strange. Please, help me to explain this. I have a class which starts infinite loop in a separate thread, and two classes which inherit it. One of the classes implements the interface to be triggered outside as std::shared_ptr, and another one class hold this interface as std::weak_ptr. Please look at the code below. Sorry for a lot of code, I was trying to be as short as it possible to reproduce the error. Why sometimes have I pure virtual call in Sender::notify function? As far as I know std::shared_ptr is reentrant.
#include <iostream>
#include <memory>
#include <thread>
#include <atomic>
#include <list>
#include <mutex>
class Thread : private std::thread {
std::atomic_bool run {true};
public:
Thread() : std::thread([this](){ thread_fun(); }) {}
void thread_fun() {
while (run) loop_iteration();
}
virtual void loop_iteration() = 0;
virtual ~Thread() {
run.exchange(false);
join();
std::cout << "Thread released." << std::endl;
}
};
class Sender : public Thread {
public:
class Signal{
public:
virtual void send() = 0;
virtual ~Signal(){}
};
void add_receiver(std::weak_ptr<Signal> receiver) {
std::lock_guard<std::mutex> lock(receivers_mutex);
receivers.push_back(receiver);
}
void notify() {
std::lock_guard<std::mutex> lock(receivers_mutex);
for (auto r : receivers)
if (auto shp = r.lock())
shp->send(); //Somethimes I get the pure virtual call here
}
private:
std::mutex receivers_mutex;
std::list<std::weak_ptr<Signal>> receivers;
void loop_iteration() override {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
notify();
}
};
class Receiver : public Thread, public Sender::Signal {
std::atomic_bool notified {false};
public:
void send() override {
notified.exchange(true);
}
private:
void loop_iteration() override {
std::this_thread::sleep_for(std::chrono::milliseconds(250));
std::cout << "This thread was " << (notified? " " : "not ") << "notified" << std::endl;
}
};
int main() {
std::shared_ptr<Thread>
receiver = std::make_shared<Receiver>(),
notifier = std::make_shared<Sender>();
std::dynamic_pointer_cast<Sender>(notifier)->add_receiver(
std::dynamic_pointer_cast<Sender::Signal>(receiver));
receiver.reset();
notifier.reset();
return 0;
}
Polymorphism doesn't work as you may expect during construction and destruction. The current type is the most derived type that still exists. When you are in Thread::~Thread the Sender part of your object has already been completely destroyed so it wouldn't be safe to call its overrides.
When thread_fun tries to run loop_iterator() before the constructor finishes or after the destructor starts, it will not polymorphically dispatch, but instead it will call Thread::loop_iteration which is a pure virtual function (= 0).
See https://en.cppreference.com/w/cpp/language/virtual#During_construction_and_destruction
Here is a demonstration of this : https://godbolt.org/z/4vsPGYq97
The derived object is destroyed after one second, at which point you see the output change indicating that the virtual function being called changes at that point.
I'm not sure if this code is valid, or if destroying the derived part of the object while one of its member function is being executed is Undefined Behavior.
In addition to what François Andrieux noted, your real problem is that you are starting the thread running, using this object, before its construction is finished. It may or may not see the derived type constructed yet, depending on timing.
It's not calling thread_fun from the constructor, as he implies. It's calling that on a different thread, at some unknown point in the future. It might happen on a different core before this base class constructor has returned, or at any other random point during the derived class's construction process, or much later.
You can't safely start the thread's function until the object is ready to be used.
Separate creation from making it go. That's the easiest thing.
meanwhile
virtual ~Signal(){}
Don't define empty destructors. Write =default instead.
But, use override in the derived class, and don't use virtual there.
You have a problem in that you assume that the spawned thread does not start immediately and the current thread has time to initialize the state of the current object before it does anything.
This does not hold which causes two issues.
You accesses state in the current object that has not been initialized.
You use a polymorphic function that is not guranteed to work until after the object is fully constructed.
You make a slight assumption in your destructor:
You inherit from an object that does not have a virtual destructor.
Your thread may still accesses state after the object has started its destruction. If it does (access destroyed) then it is UB. Your thread needs to be able to check if the current object state is valid (i.e. All derived classes must get a lock on run and make sure its state is till true and all destructors must set run to false.
Your problem lies here:
class Thread : private std::thread {
std::atomic_bool run {true};
public:
Thread()
// Here you are starting a separate thread of execution
// That calls the method thread_fun on the current object.
//
// No problem so far. BUT you should note that "this" object
// is not fully constructed at this point and there is no
// guarantees that the thread you just started will wait
// for this thread to finish before doing anything.
: std::thread([this](){ thread_fun(); })
{}
void thread_fun() {
// The new thread has just started to run.
// And is now accessing the variable `run`.
//
// But `run` is a member and initialized after
// the base class so you have no idea if the parent
// thread has correctly initialized this variable yet.
//
// There is no guratnee that the parent will get to
// the initialization point of `run` before this new thread
// gets to this point where it is using it.
while (run) {
// Here you are calling a virtual function.
// The trouble is that virtual functions are not
// guranteed to work as you would expect until all the
// constructors of the object have run.
// i.e. from base all the way to most derived.
//
// So you not only have to wait for this base class to
// be full constructed you must wait until the object
// is full constructed before you call this method.
loop_iteration();
}
}
virtual void loop_iteration() = 0;
virtual ~Thread() {
// You have a problem in that std::thread destructor
// is not virtual so you will not always call its destructor
// correctly.
//
// But lets assume it was called correctly.
// When you get to this point you have destroyed the
// the state of all derived parts of your object.
// So the function your thread is running better
// not touch any of that state as it is not all invalid
// and doing so is UB.
//
// If your object had no state then you are fine.
run.exchange(false);
join();
std::cout << "Thread released." << std::endl;
}
};
I think a better solution is to make the std::thread a member of your object, and force any threads to hold until you have the state correctly initialized (at the point where you create the object).
class Thread {
std::atomic_bool run;
std::thread thread;
public:
Thread(std::function<void>& hold)
// Make sure run is initialized before the thread.
: run{false}
, thread([this, &hold](){ thread_fun(hold); })
{}
void thread_fun(std::function<void>& hold) {
// Pass in a hold function.
// The creator of your objects defines this
// It is supposed to make objects created until you
// have all the state correctly set up.
// once it is you allow any threads that have called
// hold to be released so they can execute.
hold();
while (run) loop_iteration();
}
virtual void loop_iteration() = 0;
virtual ~Thread() {
run.exchange(false);
join();
std::cout << "Thread released." << std::endl;
}
};
Then you can create a simple barrier to use in hold:
class Barrier
{
bool threadsShouldWait = true;
std::conditional_variable cond;
std::mutex mutex;
void wait() {
std::unique_lock<std::mutex> lock(mutex);
cond.wait([&](){return !threadsShouldWait;}, lock);
}
void release() {
std::unique_lock<std::mutex> lock(mutex);
threadsShouldWait = false;
cond.notify_all();
}
}
int main()
{
// Note you don't need to use the same barrier for
// both these variables. I am just illustrating one use case.
Barrier barrier;
std::shared_ptr<Thread> receiver = std::make_shared<Receiver>([&barrier](){barrier.wait();});
std::shared_ptr<Thread> notifier = std::make_shared<Sender>([&barrier](){barrier.wait();});
barrier.release();

Cannot kill std::thread

I have a program that I need to run a thread in. The problem is whenever I try to kill this thread from either inside the thread or outside the thread I get a "error 6 - invalid handle" error
class myclass
{
public:
static myclass* inst()
{
if (oInst == nullptr) oInst = new myclass;
return oInst;
};
void main();
void start();
void ex_stop()
{
//HANDLE Stopper = Killer.native_handle();
//TerminateThread(Stopper, 0);
}
}
private:
std::thread Killer;
}
void myclass::start()
{
Killer = std::thread(&myclass::ex_main, this);
Killer.detach();
}
void myclass::main()
{
...
if (0 == TerminateThread(Killer.native_handle(), 0))
{
char error[200];
sprintf(error, "error %i\n", GetLastError());
printf(error);
}
This is how I start the class/thread
myclass::inst()->start();
I've also tried making std::thread Killer an extern and declaring it in my .cpp and .h files, this way I can access it from outside the class, but I still get the same "error 6, invalid thread handle" error.
Can someone please tell me what's wrong with this code? Thanks
The usual way of having a worker thread set up is to put it into a loop, and on each loop check to see if a boolean atomic has been changed ... something that would look like (but this probably doesn't compile straight off; the threadMain will probably need binding)
class myThreadJob {
public:
myThreadJob():
doRun(true),
thread(threadMain)
{}
void threadMain() {
while (doRun) {...}
}
void stop() {
doRun = false;
thread.join();
}
private:
std::atomic<bool> doRun;
std::thread thread;
}
You've not said if your thread is a will do many tasks in a queue, or if it's a one off job that it's doing, but in any case if it's expected to be a long lived thread, it should check periodically that it can still run.
Because you've called detach() on your thread, your thread is no longer associated with your process. You can think of detach() as a declaration that the thread does not need anything local to the creating thread.
You are not allowed to join it; and you're expecting it to run to termination.

Virtual call within thread ignores derived class

In the following program I have a virtual call from within a thread:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
class A {
public:
virtual ~A() { t.join(); }
virtual void getname() { std::cout << "I am A.\n"; }
void printname()
{
std::unique_lock<std::mutex> lock{mtx};
cv.wait(lock, [this]() {return ready_to_print; });
getname();
};
void set_ready() { std::lock_guard<std::mutex> lock{mtx}; ready_to_print = true; cv.notify_one(); }
void go() { t = std::thread{&A::printname,this}; };
bool ready_to_print{false};
std::condition_variable cv;
std::mutex mtx;
std::thread t{&A::printname,this};
};
class B : public A {
public:
int x{4};
};
class C : public B {
void getname() override { std::cout << "I am C.\n"; }
};
int main()
{
C c;
A* a{&c};
a->getname();
a->set_ready();
}
I was hoping the program would print:
I am C.
I am C.
But instead it prints:
I am C.
I am A.
In the program I wait until the derived object is fully constructed before I call the virtual member function. However the thread is started before the object is fully constructed.
How can the virtual call be assured?
The shown code exhibits a race condition, and undefined behavior.
In your main():
C c;
// ...
a->set_ready();
Immediately, after set_ready() returns, execution thread leaves main(). This results in immediate destruction of c, starting with the superclass C, and continuing to destroying B, then A.
c is declared in automatic scope. That means that as soon as main() returns, it's gone. Joined the choir invisible. It is no more. It ceased to exist. It's an ex-object.
Your join() is in the superclass's destructor. Nothing stops C from being destroyed. The destructor will only pause and wait to join the thread, when the superclass gets destroyed, but C will start getting destroyed immediately!
Once the C superclass is destroyed, its virtual method no longer exists, and invoking the virtual function will end up executing the virtual function in the base class.
Meanwhile the other execution thread is waiting on the mutex and the condition variable. The race condition is that you have no guarantee that the other execution thread will wake up and start executing before the parent thread destroys C, which it does immediately after signaling the condition variable.
All that signaling the condition variable gives you is that whatever execution thread is spinning on the condition variable, that execution thread will start executing. Eventually. That thread could, on a very loaded server, start executing seconds later, after its signaled via the condition variable. Its object is gone a long time ago. It was in automatic scope, and main() destroyed it (or, rather, the C subclass is already destroyed, and A's destructor is waiting to join the thread).
The behavior you are observing is the parent thread managing to destroy the C superclass before the std::thread gets around to making its virtual method call, after receiving the signal from the condition variable, and unlocking its mutex.
That's the race condition.
Furthermore, executing a virtual method call at the same time the virtual object is being destroyed is already a non-starter. It's undefined behavior. Even if the execution thread ends up in the overridden method, its object is being destroyed by another thread at the same time. You're pretty much screwed, at that point, no matter which way you turn.
Lessons learn: rigging up a std::thread to execute something in this object is a minefield of undefined behavior. There are ways of doing it correctly, but it's hard.
This is the most likely sequence of events:
The A part of the object is constructed, which starts a thread
The B part of the object is constructed.
The C part of the object is constructed.
getname is called on the main thread, which prints "I am C!" because it's a C.
The main thread notifies the other thread (I'll call it the printing thread)
main starts to return.
The C part of the object is destructed.
The B part of the object is destructed.
The A part of the object is destructed... but this blocks until the printing thread exits.
Now that the main thread is blocked the OS switches to the printing thread.
The printing thread calls getname, which prints "I am A!" because it's an A (with the C and B parts of the object now having been destroyed).
The printing thread exits
The main thread wakes up, finishes destroying the A part, and exits the program.
To get the expected behaviour reliably, you need to wait for the printing thread to exit before the closing } of main.
The other answers are definitive, but don't show a possible fix. Here is the same program with additional variables and waiting:
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
class A {
public:
virtual ~A() { t.join(); }
virtual void getname() { std::cout << "I am A.\n"; }
void printname()
{
std::unique_lock<std::mutex> lock{mtx};
cv.wait(lock, [this]() {return ready_to_print; });
getname();
printing_done = true;
cv.notify_one();
};
void set_ready() { std::lock_guard<std::mutex> lock{mtx}; ready_to_print = true; cv.notify_one(); }
void go() { t = std::thread{&A::printname,this}; };
bool ready_to_print{false};
bool printing_done{false};
std::condition_variable cv;
std::mutex mtx;
std::thread t{&A::printname,this};
};
class B : public A {
public:
int x{4};
};
class C : public B {
public:
~C()
{
std::unique_lock<std::mutex> lock{mtx};
cv.wait(lock, [this]() {return printing_done; });
}
void getname() override { std::cout << "I am C.\n"; }
};
int main()
{
C c;
A* a{&c};
a->getname();
a->set_ready();
}
Prints:
I am C.
I am C.

Can I use a pointer assignment to detect the start of a thread in a safe way?

I quickly wrote some kind of wrapper to ensure some functionality in a system is always executed in a defined thread context. To make the code as small as possible, I simple use a pointer assignment to check if the thread has started.
void waitForStart() {
while (_handler == nullptr) {
msleep(100); // Sleep for 100ms;
}
msleep(100); // Sleep for 100ms to make sure the pointer is assigned
}
In my opinion, this should work in any case. Even if the assignment to _handler is for unknown reason split up into two operations on a CPU.
Is my assumtion correct? Or did I miss a case where this could go wrong?
For reference a more complete example how the system looks like. There are the System, the Thread and the Handler classes:
class Handler {
public:
void doSomeWork() {
// things are executed here.
}
};
class Thread : public ThreadFromAFramework {
public:
Thread() : _handler(nullptr) {
}
void waitForStart() {
while (_handler == nullptr) {
msleep(100); // Sleep for 100ms;
}
msleep(100); // Sleep for 100ms to make sure the pointer is assigned
}
Handler* handler() const {
return _handler;
}
protected:
virtual void run() { // This method is executed as a new thread
_handler = new Handler();
exec(); // This will go into a event loop
delete _handler;
_handler = nullptr;
}
private:
Handler *_handler;
}
class System {
public:
System() {
_thread = new Thread();
_thread->start(); // Start the thread, this will call run() in the new thread
_thread->waitForStart(); // Make sure we can access the handler.
}
void doSomeWork() {
Handler *handler = _thread->handler();
// "Magically" call doSomeWork() in the context of the thread.
}
private:
Thread *_thread;
}
You missed a case where this can go wrong. The thread might exit 5 msec after it sets the pointer. Accessing any changing variable from two threads is never reliable without synchronization.

Deleting boost::thread descendant

I am trying to write a class that would run a thread upon its object creation and stop the thread once the object gets deleted.
class MyThread : public boost::thread {
public:
MyThread() : bAlive(true) {
boost::thread(&MyThread::ThreadFunction,this);
}
~MyThread() {
{
boost::unique_lock<boost::mutex> lock(Mutex);
bAlive=false;
}
ConditionVariable.notify_one();
join();
}
private:
volatile bool bAlive;
boost::mutex Mutex;
boost::condition_variable ConditionVariable;
void ThreadFunction() {
boost::unique_lock<boost::mutex> lock(Mutex);
while(bAlive) {
ConditionVariable.timed_wait(lock,boost::get_system_time()+ boost::posix_time::milliseconds(MAX_IDLE));
/*******************************************
* Here goes some code executed by a thread *
*******************************************/
}
}
};
Theoretically, I want to wake the thread up instantly as soon as it needs to be finished, so I had to use timed_wait instead of Sleep.
This works fine until I try to delete an object of this class. In most cases, it deletes normally, but occasionally it causes an error either in condition_variable.hpp, thread_primitives.hpp or crtexe.c. Sometimes I am notified that "Free Heap block 3da7a8 modified at 3da804 after it was freed", and sometimes I'm not. And yes, I'm aware of the spurious wakeups of timed_wait, in this case it's not critical.
Can you please point me to the source of my problem? What am I doing wrong?
I see what you're trying to do but it doesn't work as you expect:
MyThread foo;
default constructs a boost::thread (because MyThread is derived from boost::thread).
The default constructor creates a boost::thread instance that refers to Not-a-Thread.
MyThread() {
boost::thread(&MyThread::ThreadFunction,this);
}
is actually creating a different thread and you're ignoring the returned object (the valid thread).
~MyThread() {
// ...
join();
}
is then trying to join the default constructed thread (which throws an exception inside the destructor) and you never join the thread that actually does the work.
First of all, don't derive from boost::thread. Create a member variable instead:
class MyThread {
// ...
private:
// ...
boost::thread _thread;
};
In the constructor, create and assign a thread to that member variable:
MyThread() {
_thread = boost::thread(&MyThread::ThreadFunction,this);
}
and call its join() in your destructor.
~MyThread() {
// ...
_thread.join();
}
That should fix your problem.
However, if you simply want to exit the thread when your object is destroyed (and don't have to wake it up while its running), you can use a different approach. Remove the mutex and the condition variable and use interrupt instead. This will cause sleep() to throw an exception so you have to catch it:
void ThreadFunction() {
try {
for(;;) {
boost::this_thread::sleep(boost::posix_time::milliseconds(MAX_IDLE));
// Here goes some code executed by a thread
}
} catch( const boost::thread_interrupted& e ) {
// ignore exception: thread interrupted, exit function
}
}
This will instantly exit the ThreadFunction when the thread is interrupted. If you don't need the thread to sleep every cycle, you can replace it with boost::this_thread::interruption_point(). This will just throw an exception if the thread is interrupted.
Now you can simply interrupt the thread in the destructor:
MyThread::~MyThread() {
_thread.interrupt();
_thread.join();
}