Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Start a daemon thread that's a private method of the class?

I'm new to C++11 threading and I'm trying to do something as follows:

class Something {
public:
    void start() {
        this->task_ = std::thread(&Something::someTask, this);
        this->isRunning_ = true;
        this->task_.detach(); // I read detach will stop it from hanging
    }

    void stop() {
        this->isRunning = false;
    }

    ~Something() {
         this->stop();
    }        

private:
    std::atomic<bool> isRunning_;
    std::thread task_;
    void someTask()
    {
        while(this->isRunning_) {
            // do something forever
        }
    }
};

Something whatever;
whatever.start();

However, the thread keeps getting blocked. Like nothing after whatever.start() executes. It just hangs while the loop runs.

like image 801
oldjohn1994 Avatar asked May 21 '16 03:05

oldjohn1994


2 Answers

The usual pattern to do this is

class Something {
public:
    void start() {
        this->task_ = std::thread(&Something::someTask, this);
        // this->task_.detach(); <<<<<< Don't do that.
    }

    void stop() {
        this->isRunning_ = false;
        task_.join(); // <<<  Instead of detaching the thread, join() it.
    }

    ~Something() {
         this->stop();
    }        

private:
    std::atomic<bool> isRunning_;
    std::thread task_;
    void someTask()
    {
        this->isRunning_ = true;
        while(this->isRunning_) {
            // do something forever
        }
    }
};

Detaching a std::thread usually isn't a good idea, unless there's some kind of synchronization set up, that allows to wait for the thread execution to end before the process ends as a whole.


Demonizing a process usually is realized with a fork() to create a background child process, and leave the parent process to return control to the caller.

like image 132
πάντα ῥεῖ Avatar answered Oct 22 '22 18:10

πάντα ῥεῖ


I recently wrote a generic class that does just this

#include<functional>
#include<thread>

//do action asynchronously until condition is false
class do_async_until{
public:
    do_async_until(std::function<void(void)> action,
                   std::function<bool(void)> condition);
    ~do_async_until();
    void start();
    void stop();
private:
    void _do();
    std::thread _worker;
    std::function<void(void)> _action;
    std::function<bool(void)> _condition;
};
//implementation
do_async_until::do_async_until(std::function<void(void)> action,
               std::function<bool(void)> condition):_action(action),
                                     _condition(condition){
}
do_async_until::~do_async_until(){
    stop();
}
void do_async_until::start(){
    _worker = std::thread(std::bind(&do_async_until::_do,this));
}
void do_async_until::stop(){
    if(_worker.joinable()){
        _worker.join();
    }
}
void do_async_until::_do(){
    while (_condition())
    {
        _action();
    }
}

this will run any function with the signiture void(void) until the condition function bool(void) returns true

example usage:

int main(int agrc,char** argv){
    bool running = true;
    auto do_this = [](){
        std::cout<<"hello world"<<std::endl;
    };
    auto condition = [&](){
        return running;
    };
    do_async_until async(do_this,condition);
    async.start();
    std::this_thread::sleep_for(std::chrono::seconds(1));
    running=false;

    return 0;
}

The example should print "hello world" a bunch of times for one seconds then exit.

EDIT: to make this work with a member function you simply need to have an instance of do_async_until inside you class and pass the member function to the constructor of do_async_until using std::bind(&foo::func,this)

like image 36
Alex Zywicki Avatar answered Oct 22 '22 17:10

Alex Zywicki