2016-05-21 2 views
4

Я новичок в C++ 11 резьбы, и я пытаюсь сделать что-то выглядит следующим образом:Запустите поток демона, который является частным методом класса?

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(); 

Однако, поток продолжает получать заблокирован. Как ничто после whatever.start() выполняет. Он просто зависает во время цикла.

+1

Поместите эту строку 'this-> isRunning_ = true; 'above' this-> task_ = std :: thread (& Something :: someTask, this); '. В противном случае цикл потока может завершиться до того, как вы установите условие для его запуска. –

+0

@ πάνταῥεῖ Спасибо. По какой-то причине петля теперь исчезает мгновенно. – oldjohn1994

+0

Просто проголосовали, чтобы закрыть это. Очевидная причина, по которой она не соответствует теме, заключается в том, что ей не хватает полного, но минимального кода для воспроизведения проблемы. Кроме того, эта тема вводит в заблуждение, было обнаружено очевидное состояние гонки, но впоследствии игнорируется, и в тексте слишком много интерпретации (в отличие от наблюдения). Таким образом, это не является полезной записью для кого-либо еще. –

ответ

5

Обычная картина сделать это

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 
     } 
    } 
}; 

Отсоединение std::thread обычно не является хорошей идеей, если нет какой-то синхронизации настройки, что позволяет ждать выполнения потока в до завершения процесса в целом.


Demonizing процесс обычно реализуется с fork(), чтобы создать дочерний процесс фона и оставить родительский процесс вернуть управление вызывающему.

+0

Я реализовал это, и теперь он бросает «завершение вызова без активного исключения». – oldjohn1994

+1

Мой плохой, он работает, я забыл добавить «join()» к деструктору, большое спасибо – oldjohn1994

+0

Настройка isRunning to true в методе run - это рецепт состояния гонки. Это должно быть сделано в начале перед началом потока. – Voo

1

Недавно я написал общий класс, который делает именно это

#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(); 
    } 
} 

это будет запускать любую функцию с signiture пустоту (пустоты), пока условие функции BOOL (аннулируются) возвращает истинное

пример использования:

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; 
} 

Пример должен напечатать «привет мир» кучу раз в течение одной секунды, затем выйти.

EDIT: чтобы сделать эту работу с функцией члена просто нужно иметь экземпляр do_async_until внутри вас класса и передать функции члена конструктору do_async_until с помощью std::bind(&foo::func,this)

+0

В чем разница между 'async' и' future' (http://en.cppreference.com/w/cpp/thread/future)? –

+0

Насколько мне известно, std :: async не подходит для использования, когда порожденная нить будет сохраняться в течение более длительного периода времени. std :: async, кажется, лучше всего подходит для одних вычислений, где, как я полагаю, мой дизайн ближе к постоянному рабочему потоку. std :: async теоретически можно использовать для достижения того же результата, но std :: async не дает обещаний относительно того, действительно ли задача будет завершена в другом потоке или на месте, даже если вы укажете std :: launch :: async. См. Http://en.cppreference.com/w/cpp/thread/async –

+0

Насколько я вижу, образец поврежден - работа должна быть std :: atomic для этого, чтобы не вызывать UB. – Voo

Смежные вопросы