【问题标题】:C++17 async: running a this' method blocks the whole objectC++17 异步:运行 this' 方法会阻塞整个对象
【发布时间】:2016-11-17 19:25:26
【问题描述】:

我正在开发一款游戏。假设有一个对象 LoadingState 具有这些方法(以及其他一些方法):

  • 创建
  • 更新
  • 加载

每次 CPU 时钟滴答时都会调用更新,而创建只会调用一次,它应该调用加载函数(异步),以加载一些游戏资源。在 create 函数内异步调用 load 允许(理论上)在 create/load 执行时从调用的 beling 更新。然而,这并没有发生。

在 Visual Studio 2015 之前,我是这样使用 std::async 的:

std::async(&LoadingState::load, this, THE_ASSETS_PATHS_STRING_VECTOR);

在迁移到 Visual Studio 2015 (C++17) 并读取必须指定 std::launch 后,否则可能会发生意外行为,现在异步调用如下:

std::async(std::launch::async, &LoadingState::load, this, THE_ASSETS_PATHS_STRING_VECTOR);

换句话说,在我看来,'this' 被 std::async 锁定,阻塞了整个对象,阻止了主线程调用更新。

更多相关代码:

void LoadingState::onCreate()
{
    std::vector<std::string> assets;

    assets.push_back("Images/Scenario/wall.png");
    assets.push_back("Images/Scenario/bigdummy.png");
    assets.push_back("Images/Scenario/buildings.png");
    assets.push_back("Images/Scenario/floor.png");
    assets.push_back("Images/Scenario/terrain.png");
    assets.push_back("Images/Scenario/trees.png");

    // Load assets asynchronously
    std::async(std::launch::async, &LoadingState::load, this, assets);
}

void LoadingState::load(std::vector<std::string> assets)
{
    unsigned int count = 0;
    unsigned int ratio = 100U / assets.size();

    // Cache the asset accordingly
    for (auto& asset : assets)
    {
        // Load and store the asset
        // ...

        // Asset loaded
        count++;

        // Calculate the progress by count
        m_progress = count * ratio;
    }

    // If assets were skipped or progress would be like 98% due to truncation, normalize it
    m_progress = 100U;
}


void LoadingState::update(float delta)
{
    // ...

    // If finished loading the resources, move on to playing state!
    if (m_progress >= 100U) {
        m_machine->next(new PlayingState(m_machine));
    }
}

我在这里误会了什么?!

PS:在迁移之前,所有东西都可以顺利运行。

【问题讨论】:

  • 在 C++11 之前,我向你保证你没有使用 std::async!
  • THE_ASSETS_PATHS_STRING_VECTOR 也不存在。你的批评/讽刺没有帮助。
  • "Visual Studio 2015 (C++17)" VS 2015 不包含 C++17。它包含最多的C++17位。
  • 除非你捕捉到std::async返回的std::future,否则它将总是阻塞。
  • @YvesHenri 实际上,我弄错了。该标准不要求它阻止,但它可能。请参阅 N4296 中的 30.6.8.5 [futures.async]。

标签: multithreading c++11 asynchronous mutex stdasync


【解决方案1】:
std::async(std::launch::async, &LoadingState::load, this, assets);

asyncwill block in its destructor until the async function has finished 返回的future(与其他future 对象不同)。因此,您必须捕获该future 并使其保持活动状态(在必要时移动它),直到您准备好回答为止。

或者您可以停止使用 async 等不合理的功能。

读到必须指定 std::launch

不,它没有。

【讨论】:

  • async 并没有错。它只是没有给出适当的默认值。 C++14 解决了这个问题。您在上下文中引用了 OP:“必须指定 std::launch,否则可能会发生意外行为。”从 C++14 开始就是这样。
  • "如果既没有 std::launch::async 也没有 std::launch::deferred,也没有在 policy 中设置任何实现定义的策略标志,则行为未定义。" - en.cppreference.com/w/cpp/thread/async
  • @YvesHenri:调用第一个重载将调用第二个重载,同时提供这两个参数。这不是未定义的行为;这只是通过函数重载的默认参数。
  • 无论如何,没有其他方法可以在不存储未来的情况下使用异步?如果我不直接处理它,除了让 async 异步运行之外,保留它似乎很奇怪。
  • @YvesHenri:“没有其他方法可以在不存储未来的情况下使用异步?No。这就是我称其为“不合时宜”的原因之一。
猜你喜欢
  • 2019-01-08
  • 2012-08-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多