对未来对象进行更改

时间:2014-03-13 04:56:36

标签: visual-studio-2012 c++11

我正在尝试根据用户输入更改未来对象的行为。

#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 个答案:

答案 0 :(得分:1)

你有一些问题。首先,您的函数对象实际上不会返回int,因此std::async将返回std::future<void>。您可以通过从int实际返回DoWork::operator(),或将async中的结果存储在std::future<void>而不是尝试打印来解决此问题。

其次,std::async复制它的参数,如果它们不在引用包装器中,那么堆栈上的doObj将不会是正在使用的DoWork的同一个实例由异步线程。您可以通过在doObj的参考包装中传递std::async(std::launch::async, std::ref(doObj))来更正此问题。

第三,主线程和异步线程同时访问DoWork::_stop。这是数据竞争,意味着程序具有未定义的行为。修复方法是使用_stop保护对std::mutex的访问权限,或将其设为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;
}
//=======================================================================================!
相关问题