2014-03-13 70 views
0

我正在嘗試根據用戶輸入更改未來對象的行爲。更改未來對象

#include <iostream> 
#include <future> 

//=======================================================================================! 
struct DoWork 
{ 

    DoWork(int cycles, int restTime) : _cycles(cycles), _restTime(restTime), _stop(false) 
    { 
    } 

    void operator()() 
    { 
     for(int i = 0 ; i < _cycles; ++i) 
     { 
      std::this_thread::sleep_for(std::chrono::milliseconds(_restTime)); 
      if(_stop)break; 

      doTask(); 
     } 
    } 

    void stop() 
    { 
     _stop = true; 
    } 

private: 
    void doTask() 
    { 
     std::cout << "doing task!" << std::endl; 
    } 

private: 
    int _cycles; 
    int _restTime; 
    bool _stop; 
}; 

//=======================================================================================! 

int main() 
{ 
    DoWork doObj(50, 500); 
    std::future<int> f = std::async(std::launch::async, doObj); 

    std::cout << "Should I stop work ?" << std::endl; 
    std::cout << "('1' = Yes, '2' = no, 'any other' = maybe)" << std::endl; 
    int answer; 
    std::cin >> answer; 

    if(answer == 1) doObj.stop(); 

    std::cout << f.get() << std::endl; 
    return 0; 
} 
//=======================================================================================! 

但是,這並不會停止執行未來的對象。如何在創建未來對象後更改doObj的行爲?

回答

1

你有幾個問題。首先,你的函數對象實際上並不返回int,所以std::async將返回一個std::future<void>。您可以通過從DoWork::operator()實際返回int或通過將async的結果存儲在std::future<void>中而不嘗試打印它來解決此問題。

其次,std::async會將它的參數,如果他們不參考的外包裝,所以堆棧上的doObj不會是正在使用的異步線程的DoWork相同的實例。您可以通過在參考包裝中傳遞doObj來糾正此錯誤,例如la std::async(std::launch::async, std::ref(doObj))

三,主線程和異步線程同時訪問DoWork::_stop。這是一場數據競賽,意味着該程序具有未定義的行爲。修復方法是使用std::mutex保護對_stop的訪問或使其成爲std::atomic

總之,程序應該像(Live at Coliru):

#include <iostream> 
#include <future> 

//=======================================================================================! 
struct DoWork 
{ 
    DoWork(int cycles, int restTime) : _cycles(cycles), _restTime(restTime), _stop(false) 
    { 
    } 

    int operator()() 
    { 
     for(int i = 0 ; i < _cycles; ++i) 
     { 
      std::this_thread::sleep_for(std::chrono::milliseconds(_restTime)); 
      if(_stop) return 42; 

      doTask(); 
     } 
     return 13; 
    } 

    void stop() 
    { 
     _stop = true; 
    } 

private: 
    void doTask() 
    { 
     std::cout << "doing task!" << std::endl; 
    } 

private: 
    int _cycles; 
    int _restTime; 
    std::atomic<bool> _stop; 
}; 

//=======================================================================================! 

int main() 
{ 
    DoWork doObj(50, 500); 
    std::future<int> f = std::async(std::launch::async, std::ref(doObj)); 

    std::cout << "Should I stop work ?" << std::endl; 
    std::cout << "('1' = Yes, '2' = no, 'any other' = maybe)" << std::endl; 
    int answer; 
    std::cin >> answer; 

    if(answer == 1) doObj.stop(); 

    std::cout << f.get() << std::endl; 
} 
//=======================================================================================!