C++ threads does not work as I expect? - c++

I am making bigger program where I want to use threads so as first I am trying to find out how threads actually work so I created a simple program and I can not understand why I do not get a message "Bomberman has just put a bomb. Wait for the boom." earlier than "The bomb has just detonated.".
Can anyone instruct me why is it not working as I expect?
#include <unistd.h>
#include <chrono>
#include <iostream>
#include <thread>
using namespace std;
class CBomberman;
class CBomb {
public:
CBomb(void) : m_Owner(nullptr) {
thread other_thread(&CBomb::Timer, this);
other_thread.join();
}
private:
void Timer(void) {
this_thread::sleep_for(chrono::seconds(3));
cout << "The bomb has just detonated." << endl;
}
CBomberman* m_Owner;
};
class CBomberman {
public:
CBomberman(void) : m_Bomb(nullptr) {}
bool PutBomb(void) {
if (m_Bomb == nullptr) {
m_Bomb = new CBomb();
delete m_Bomb;
return true;
} else {
cout << "The bomb has already been put." << endl;
return false;
}
}
private:
CBomb* m_Bomb;
};
int main() {
CBomberman bomberman;
bomberman.PutBomb();
cout << "Bomberman has just put a bomb. Wait for the boom." << endl;
return 0;
}

Your problem is that you're joining the thread immediately after you create it, meaning that you're only using multithreading in a very technical sense: you've definitely created another thread, and it's (probably) going to operate on another CPU core, but the host thread is simply sitting idle while the other thread works.
You need to locally store the thread object so that you can join it at a later point.
class CBomb
{
public:
CBomb ( void )
: m_Owner ( nullptr ),
bomb_thread(&CBomb::Timer, this)
{
}
std::thread bomb_thread; //This needs to be a member of this object. Whether you make it public or not is a matter of your design approach.
private:
void Timer ( void )
{
this_thread::sleep_for( chrono::seconds( 3 ) );
cout << "The bomb has just detonated." << endl;
}
CBomberman * m_Owner;
};
class CBomberman
{
public:
CBomberman ( void )
: m_Bomb ( nullptr )
{
}
bool PutBomb ( void )
{
if( m_Bomb == nullptr )
{
m_Bomb = new CBomb();//Don't delete the object immediately after creating it. What were you expecting to have happen if you did?
return true;
}
else
{
cout << "The bomb has already been put." << endl;
return false;
}
}
CBomb * m_Bomb;
};
int main()
{
CBomberman bomberman;
bomberman.PutBomb();
cout << "Bomberman has just put a bomb. Wait for the boom." << endl;
bomberman.m_bomb->bomb_thread.join(); //If we hit the end before the thread concludes, there could be some errors.
return 0;
}

Because you call join on other_thread immediately after creating other_thread. The join call blocks the main thread and waits for other_thread to exit. See docs on std::thread::join at http://en.cppreference.com/w/cpp/thread/thread/join.

Related

create a monitor class in C++ that terminates gracefully [duplicate]

This question already has answers here:
How do I terminate a thread in C++11?
(7 answers)
How to stop the thread execution in C++
(3 answers)
Proper way to terminate a thread in c++
(1 answer)
Closed 3 years ago.
My main function loads a monitoring class. This class calls external services to periodically get some data and report health status.
These are the task_1 and task_2 in the class below, that can have sub tasks. The tasks accumulate some values that are stored to a shared "Data" class.
So each task_N is coupled with a thread that executes, sleeps for a while and does this forever until the program stops.
My basic problem is that I cannot stop the threads in the Monitor class, since they might be waiting for the timer to expire (sleep)
#include <iostream>
#include <thread>
#include <utility>
#include "Settings.hpp"
#include "Data.hpp"
class Monitors {
public:
Monitors(uint32_t timeout1, uint32_t timeout2, Settings settings, std::shared_ptr<Data> data)
: timeout_1(timeout1), timeout_2(timeout2), settings_(std::move(settings)), data_(std::move(data)) {}
void start() {
thread_1 = std::thread(&Monitors::task_1, this);
thread_2 = std::thread(&Monitors::task_2, this);
started_ = true;
}
void stop() {
started_ = false;
thread_1.join();
thread_2.join();
std::cout << "stopping threads" << std::endl;
}
virtual ~Monitors() {
std::cout << "Monitor stops" << std::endl;
}
private:
void subtask_1_1() {
//std::cout << "subtask_1_1 reads " << settings_.getWeb1() << std::endl;
}
void subtask_1_2() {
//std::cout << "subtask_1_2" << std::endl;
data_->setValue1(21);
}
void task_1() {
while(started_) {
subtask_1_1();
subtask_1_2();
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_1));
std::cout << "task1 done" << std::endl;
}
}
void subtask_2_1() {
//std::cout << "subtask_2_1" << std::endl;
}
void subtask_2_2() {
//std::cout << "subtask_2_2" << std::endl;
}
void task_2() {
while(started_) {
subtask_2_1();
subtask_2_2();
std::this_thread::sleep_for(std::chrono::milliseconds(timeout_2));
std::cout << "task2 done" << std::endl;
}
}
private:
bool started_ {false};
std::thread thread_1;
std::thread thread_2;
uint32_t timeout_1;
uint32_t timeout_2;
Settings settings_;
std::shared_ptr<Data> data_;
};
The main function is here:
auto data = std::make_shared<Data>(10,20);
Settings set("hello", "world");
Monitors mon(1000, 24000,set,data);
mon.start();
int count = 1;
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << data->getValue2() << " and count is " << count << std::endl;
count++;
if ( count == 10)
break;
}
std::cout << "now I am here" << std::endl;
mon.stop();
return 0;
Now when I call mon.stop() the main thread stops only when the timer exprires.
How can I gracefully call mon.stop() and interrupt and call the task_N?
UPDATE: Since I don't want to call std::terminate, which is the proper way to implement a monitor class in c++

What is the correct way to run tracking software and a server concurrently? (OpenCV 3)

I have written a basic server in C++ that runs in an infinite while loop. It receives signals from a client to do things. The main process that I want is to initiate or stop some tracking software that I have written.
I would like the server to still be able to receive signals while the tracking software is being run (e.g. if a stop signal was given). I figured that the best way to do this would be to create a separate thread for the tracking software, so that is what I did:
void Server::tracking(Command c)
{
//I have since changed this method. The new implementation is below
//switch(c) {
// case START:
// player = VideoPlayer();
// player.setTrackStatus(true);
// t = std::thread(&Server::track, this);
// t.detach();
// break;
// case STOP:
// player.setTrackStatus(false);
// break;
// default:
// break;
//}
}
Server::track just calls player.run()
VideoPlayer is the class that contains the main tracking loop. The track status is what determines whether or not the tracking loop continues to execute.
This works fine the first time I run it, it is able to start the tracking and stop it. The problem arises when I try to send another "START" signal without restarting the server.
I have narrowed down the problem to the cv::namedWindow function.
Here is the start of the VideoPlayer class:
void VideoPlayer::run(void)
{
//I have since changed this method. The new implementation is below
//initVC();
//openStream();
}
initVC() is where I create the namedWindow and openStream contains the main tracking loop. Here is initVC (which is where I believe the problem lies):
void VideoPlayer::initVC()
{
if(!capture.open("cut.mp4")) {
throw "Cannot open video stream";
}
std::cout << "flag 1" << std::endl;
cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
std::cout << "flag 2" << std::endl;
}
I have found that on the second run (i.e. tracking has been started and stopped and the server has not been closed and reopened), that flag 2 never gets run. I also found that, if I omit namedWindow then the program stops before imshow(). It might also be worth noting that the program doesn't crash, it just seems to pause.
I have a feeling that I am doing something wrong with the threading, because I have never used threads in C++ before.
Thanks!
EDIT: I have been attempting to add some of the changes suggested by #Dom, however I am still having a similar issue to before. I will post some additional code below with comments to try to explain.
Server::tracking:
This is meant to initiate tracking based on the command received from the client.
void Server::tracking(Command c)
{
switch(c) {
case START:
if(!isRunning) {
player = make_unique<VideoPlayer>();
isRunning = true;
player->setTrackStatus(isRunning);
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
case STOP:
if(isRunning) {
player->terminate();
player->exit(); //Destroys OpenCV stuff
player->joinThread();
player = nullptr;
isRunning = false;
}
else {
std::lock_guard<std::mutex> lock(mtx);
}
break;
default:
break;
}
}
VideoPlayer Constructor:
VideoPlayer::VideoPlayer () : trackStatus(true)
{
tracker = Tracker(); //A separate class, related to the data from the tracked
//object. Not relevant to the current question
track_t = std::thread(&VideoPlayer::run, this);
return;
}
VideoPlayer::run:
void VideoPlayer::run(void)
{
std::lock_guard<std::mutex> lock(mtx);
initVC(); //Initialises the OpenCV VideoCapture
openStream(); //Contains the main tracking code
return;
}
VideoPlayer::openStream:
void VideoPlayer::openStream()
{
while(trackStatus) {
... //tracking stuff
}
return;
}
VideoPlayer::terminate:
void VideoPlayer::terminate()
{
track = false;
std::lock_guard<std::mutex> lock(mtx);
}
VideoPlayer::joinThread:
void VideoPlayer::joinThread()
{
if(track_t.joinable()) {
std::cout << "flag 1" << std::endl;
track_t.join();
std::cout << "flag 2" << std::endl; //It fails here on my second "run"
return;
}
}
Basically, my program stops just before the track_t.join(), the second time I run the tracking (without restarting the server). flag 1 and flag 2 print the first time that I run the tracking. All of the OpenCV components appear to have been disposed of correctly. If I then try to open the tracking again, firstly, the tracking doesn't seem to start (but the program doesn't crash), and then if I try to stop the tracking, it prints flag 1 but then stops indefinitely without printing flag 2
Sorry for the lengthy post. I hope this gives a bit more context to what I'm trying to achieve
So your tracking app. could be implemented as follows:
#include <chrono>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <memory>
#include <atomic>
enum Command : char
{
START = '1',
STOP = '0'
};
static std::mutex mtx; // mutex for I/O stream
class VideoPlayer
{
public:
VideoPlayer() : trackStatus()
{
initVC();
openStream();
};
~VideoPlayer()
{
closeStream();
uninitVC();
}
void setTrackStatus(bool status)
{
if (status && trackStatus == false)
{
trackStatus = status;
t = std::thread(&VideoPlayer::run, this);
}
else
{
trackStatus = false;
if (t.joinable())
{
t.join();
}
}
}
private:
void run()
{
tId = std::this_thread::get_id();
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "run thread: " << tId << std::endl;
}
while (trackStatus)
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "...running thread: " << tId << std::endl;
}
std::this_thread::sleep_for(std::chrono::seconds(1)); // encode chunk of stream and play, whatever....
}
}
void initVC()
{
/*
if (!capture.open("cut.mp4"))
{
throw "Cannot open video stream"; --> http://stackoverflow.com/questions/233127/how-can-i-propagate-exceptions-between-threads
}
std::cout << "flag 1" << std::endl;
//cv::namedWindow("Tracker", CV_WINDOW_AUTOSIZE);
//std::cout << "flag 2" << std::endl;
*/
}
void uninitVC()
{
}
void openStream()
{
}
void closeStream()
{
}
private:
std::atomic<bool> trackStatus; // atomic, because of access from another (main) thread
std::thread t; // thread for "tracking"
std::thread::id tId; // ID of the "tracking" thread
};
class Server
{
public:
Server() : isRunning(), player(std::make_unique<VideoPlayer>())
{
}
~Server() = default;
void tracking(Command c)
{
switch (c)
{
case START:
if (!isRunning)
{
isRunning = true;
player->setTrackStatus(isRunning);
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is already running...\n";
}
break;
case STOP:
if (isRunning)
{
player->setTrackStatus(!isRunning);
isRunning = false;
}
else
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "Player is not running...\n";
}
break;
default:
break;
}
}
private:
std::unique_ptr<VideoPlayer> player;
bool isRunning;
};
int main()
{
std::cout << "main thread: " << std::this_thread::get_id() << std::endl;
Server srv;
char cmd = -1;
while (std::cin >> cmd)
{
switch (cmd)
{
case Command::START:
{
srv.tracking(Command::START);
}
break;
case Command::STOP:
{
srv.tracking(Command::STOP);
}
break;
default:
std::cout << "Unknown command...\n";
break;
}
}
}
You can move creation of the thread to constructor of VideoPlayer and join in destructor (I would prefer it...):
VideoPlayer() : trackStatus(true)
{
initVC();
openStream();
t = std::thread(&VideoPlayer::run, this);
};
~VideoPlayer()
{
closeStream();
uninitVC();
if (t.joinable())
{
t.join();
}
}
but some modifications are needed to terminate and clean the thread, you can use something like
public:
void VideoPlayer::terminate()
{
{
std::lock_guard<std::mutex> lock(mtx);
std::cout << "terminate thread: " << tId << std::endl;
}
trackStatus = false;
}
however, than is needed to create instance of player during START
player = std::make_unique<VideoPlayer>();
and then Terminate() and delete the player during STOP
player->terminate();
player = nullptr;
Hope, this inspired you enough ;-)

Boost thread showing no output on stdout

I'm trying to use the boost thread library. Below is a sample code.
For some reason I'm not seeing any output.
int main()
{
myclass Class1;
while(1) {
}
}
/************************************/
typedef boost::shared_ptr<boost::thread> thread_ptr;
// class definition
myclass::myclass()
{
// thread_ptr is of type thread_ptr
threat_ptr1 = thread_ptr(new boost::thread(&myclass::function_name, this));
}
void myclass:function_name()
{
std::cout << "enter here";
while( true ) {
boost::this_thread::sleep(boost::posix_time::seconds(2));
// do some stuff
}
}
Instead of
std::cout << "enter here";
use
std::cout << "enter here" << std::endl;
Flushing is your friend ;-)
As a sidenote, in production you should not use while(1){} instead of join(). What a waste of CPU time.

Mutex unlock fails strangely

I am playing around with some sockets, thread and mutexes. My question concerns threads and mutexes:
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
this->connectionList_mutex.unlock();
}
}`
The main function is running in one thread, while the addNewSocket is called by another thread. The problem is, that when addNewSocket is called once (by the second thread), the next unlock by thread 1 (main) will fail with a strange "signal SIGABRT". I have worked two days on this now, but i did not manage to get it fixed, sadly. I hope you can help me.
Edit: ConnectionHandler is a class, that has connectionList_mutex as a member.
Edit: Sometimes i also get this error: "Assertion failed: (ec == 0), function unlock, file /SourceCache/libcxx/libcxx-65.1/src/mutex.cpp, line 44." but it occurs randomly.
Edit: This is the whole class (Reduced to a minimum, should be context independant to a certain degree, but crashes when i put it right after a client connected, and works if i put it right after the start:
class ConnectionHandler{
public:
ConnectionHandler();
int addNewSocket();
private:
int main();
static void start(void * pThis);
std::mutex connectionList_mutex;
};
ConnectionHandler::ConnectionHandler(){
std::thread t(&this->start, this);
t.detach();
}
void ConnectionHandler::start(void * pThis){
ConnectionHandler *handlerThis;
handlerThis = (ConnectionHandler *)pThis;
handlerThis->main();
}
int ConnectionHandler::addNewSocket(){
this->connectionList_mutex.lock();
std::cout << "test1" << std::endl;
this->connectionList_mutex.unlock();
return 0;
}
int ConnectionHandler::main(){
while(true){
this->connectionList_mutex.lock();
std::cout << "test2" << std::endl;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
this->connectionList_mutex.unlock();
}
}
My guess is that your ConnectionHandler object is being destroyed somewhere. Also, you have defined ConnectionHandler::start in a silly way.
First, ConnectionHandler::start should be defined this way:
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
The C++11 ::std::thread class is perfectly capable of preserving the type of the function argument so there is no need to resort to void *.
Secondly, add in this code:
void ConnectionHandler::~ConnectionHandler(){
const void * const meptr = this;
this->connectionList_mutex.lock();
::std::cout << "ConnectionHandler being destroyed at " << meptr << ::std::endl;
this->connectionList_mutex.unlock();
}
And change the constructor to read:
ConnectionHandler::ConnectionHandler(){
const void * const meptr = this;
::std::cout << "ConnectionHandler being created at " << meptr << ::std::endl;
std::thread t(&this->start, this);
t.detach();
}
This will show you when the ConnectionHandler object is being destroyed. And my guess is that your code is destroying it while your detached thread is still running.
The meptr thing is because operator << has an overload for void * that prints out the pointer value. Printing out the pointer value for this will allow you to match up calls to the constructor and destructor if you're creating multiple ConnectionHandler objects.
Edit: Since it turned out I was correct, here is how I would recommend you write the play ConnectionHandler class:
#include <iostream>
#include <atomic>
#include <thread>
#include <chrono>
#include <mutex>
class ConnectionHandler {
public:
ConnectionHandler();
~ConnectionHandler();
ConnectionHandler(const ConnectionHandler &) = delete;
const ConnectionHandler &operator =(const ConnectionHandler &) = delete;
int addNewSocket();
private:
int main();
static void start(ConnectionHandler * pThis);
::std::mutex connectionList_mutex;
volatile ::std::atomic_bool thread_shutdown;
::std::thread thread;
};
ConnectionHandler::ConnectionHandler()
: thread_shutdown(false), thread(&this->start, this)
{
}
ConnectionHandler::~ConnectionHandler()
{
thread_shutdown.store(true);
thread.join();
}
void ConnectionHandler::start(ConnectionHandler * pThis){
pThis->main();
}
int ConnectionHandler::addNewSocket(){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test1" << ::std::endl;
return 0;
}
int ConnectionHandler::main(){
while(!thread_shutdown.load()){
::std::lock_guard< ::std::mutex> lock(connectionList_mutex);
::std::cout << "test2" << ::std::endl;
::std::this_thread::sleep_for(::std::chrono::milliseconds(100));
}
return 0;
}

How can I prevent a deadline timer from calling a function in a deleted class?

I have problem in a piece of real-life code, where a function belonging to a deleted class is called by a boost::asio::deadline_timer, occasionally leading to a segmentation fault.
The issue I'm having is that the deletion of the deadline_timer is run from another timer on the same io_service. The deletion of the first deadline_timer will trigger one final call to the function to be run, with a boost::asio::error::operation_aborted error. However this can only be scheduled on the (same) io_service after the delete has finished, but by then the object is already deleted and thus no longer valid.
So my question is: how can I prevent this from happening?
The following is a simplified example with the same fault:
//============================================================================
// Name : aTimeToKill.cpp
// Author : Pelle
// Description : Delete an object using a timer, from a timer
//============================================================================
#include <iostream>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include <boost/asio.hpp>
#include <boost/thread.hpp>
using namespace std;
using namespace boost;
struct TimeBomb
{
bool m_active;
asio::deadline_timer m_runTimer;
TimeBomb(boost::asio::io_service& ioService)
: m_active(true)
, m_runTimer(ioService)
{
cout << "Bomb placed #"<< hex << (int)this << endl;
m_runTimer.expires_from_now(boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, this, _1));
}
~TimeBomb()
{
m_active = false;
m_runTimer.cancel();
cout << "Bomb defused #"<< hex << (int)this << endl;
}
void executeStepFunction(const boost::system::error_code& error)
{
// Canceled timer
if (error == boost::asio::error::operation_aborted)
{
std::cout << "Timer aborted: " << error.message() << " #" << std::hex << (int)this << std::endl;
return;
}
if (m_active)
{
// Schedule next step
cout << "tick .." <<endl;
m_runTimer.expires_from_now(
boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, this, _1));
}
}
};
struct BomberMan
{
asio::deadline_timer m_selfDestructTimer;
TimeBomb* myBomb;
BomberMan(boost::asio::io_service& ioService)
: m_selfDestructTimer(ioService)
{
cout << "BomberMan ready " << endl;
myBomb = new TimeBomb(ioService);
m_selfDestructTimer.expires_from_now(boost::posix_time::millisec(10500));
m_selfDestructTimer.async_wait(boost::bind(&BomberMan::defuseBomb, this, _1));
}
void defuseBomb(const boost::system::error_code& error)
{
cout << "Defusing TimeBomb" << endl;
delete myBomb;
}
};
int main()
{
boost::asio::io_service m_ioService;
BomberMan* b = new BomberMan(m_ioService);
m_ioService.run();
return 0;
}
./aTimeToKill
BomberMan ready
Bomb placed #9c27198
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
tick ..
Defusing TimeBomb
Bomb defused #9c27198
Timer aborted: Operation canceled #9c27198
The last line is printed after the delete, illustrating my problem.
The typical recipe to solve this problem is to use a shared_ptr
#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/shared_ptr.hpp>
#include <iostream>
using namespace std;
struct TimeBomb : public boost::enable_shared_from_this<TimeBomb>
{
bool m_active;
boost::asio::deadline_timer m_runTimer;
TimeBomb(boost::asio::io_service& ioService)
: m_active(true)
, m_runTimer(ioService)
{
cout << "Bomb placed #"<< hex << this << endl;
m_runTimer.expires_from_now(boost::posix_time::millisec(1000));
}
void start()
{
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, shared_from_this(), _1));
}
void stop()
{
m_runTimer.cancel();
}
~TimeBomb()
{
m_active = false;
m_runTimer.cancel();
cout << "Bomb defused #"<< hex << this << endl;
}
void executeStepFunction(const boost::system::error_code& error)
{
// Canceled timer
if (error == boost::asio::error::operation_aborted)
{
std::cout << "Timer aborted: " << error.message() << " #" << std::hex << this << std::endl;
return;
}
if (m_active)
{
// Schedule next step
cout << "tick .." <<endl;
m_runTimer.expires_from_now(
boost::posix_time::millisec(1000));
m_runTimer.async_wait(boost::bind(&TimeBomb::executeStepFunction, shared_from_this(), _1));
}
}
};
struct BomberMan
{
boost::asio::deadline_timer m_selfDestructTimer;
boost::shared_ptr<TimeBomb> myBomb;
BomberMan(boost::asio::io_service& ioService)
: m_selfDestructTimer(ioService)
{
cout << "BomberMan ready " << endl;
myBomb.reset( new TimeBomb(ioService) );
myBomb->start();
m_selfDestructTimer.expires_from_now(boost::posix_time::millisec(10500));
m_selfDestructTimer.async_wait(boost::bind(&BomberMan::defuseBomb, this, _1));
}
void defuseBomb(const boost::system::error_code& error)
{
cout << "Defusing TimeBomb" << endl;
myBomb->stop();
}
};
int main()
{
boost::asio::io_service m_ioService;
BomberMan* b = new BomberMan(m_ioService);
m_ioService.run();
return 0;
}
This is why you have boost::shared_ptr and boost::enable_shared_from_this. Inherit TimeBomb class from boost::enable_shared_from_this like this:
struct TimeBomb : public boost::enable_shared_from_this< TimeBomb >
{
...
}
Instantiate a shared ptr instead of bare ptr:
boost::shared_ptr< TimeBomb > myBomb;
...
myBomb.reset( new TimeBomb(ioService) );
And finally in TimeBomb use shared_from_this() instead of this to construct handlers.
m_runTimer.async_wait( boost::bind( &TimeBomb::executeStepFunction, shared_from_this(), _1));
And of course TimeBomb class should expose a cancel method, through which you cancel an async operation, not by deleting, or in this case, resetting a shared_ptr.
The shared_ptr answer from Sam Miller works because the use of a shared_ptr keeps the TimeBomb hanging around for the lifetime of BomberMan. This might be ok for you, or it might not.
A suggestion for a more complete solution would be to obtain your TimeBomb instances from a factory which you then release them back to when finished, rather than newing and deleting them explicitly (holding them as standard pointers, not shared_ptrs as you don't own them even though you are controlling the lifecycle). The factory can keep them hanging around until they are cancelled and then delete them for you. Keep Sam Miller's stop() function as is.
To implement this, derive the factory from an interface along the lines of
class ITimeBombObserver
{
public:
virtual void AllOperationsComplete(TimeBomb& TmBmb)=0;
};
Pass your factory to each TimeBomb as the ITimeBombObserver on construction, and have the cancellation of the TimeBomb call this function. The factory can clean up "used" TimeBombs each time one is created or released, or using a scheduled cleanup, or some other method, whichever seems most appropriate for your application.
Using this method your BomberMan doesn't even need to explicitly release the TimeBomb in defuseBomb() if it doesn't want, the call to stop() can auto release (although in this case you should still null the pointer as it becomes effectively unusable at this point). Whether this is a good idea or not depends on your real problem, so I'll leave it to you to decide.
For a really simple fix, how about this? (I've only included the bits you need to change)
It works because you only access stack variables on a timer cancel. You don't really need to callback the handler at all in the destructor of course, but I'm assuming your real code requires this for whatever reason.
~TimeBomb()
{
m_active = false;
executeStepFunction(boost::asio::error::interrupted);
m_runTimer.cancel();
cout << "Bomb defused #"<< hex << (int)this << endl;
}
void executeStepFunction(const boost::system::error_code& error)
{
// Canceled timer
if (error == boost::asio::error::operation_aborted)
{
return;
}
if (error == boost::asio::error::interrupted)
{
std::cout << "Timer aborted: " << error.message() << " #" << std::hex << (int)this << std::endl;
return;
}
...