C++从 std::async 函数读取命名空间中的全局变量标志



所以我的用例如下:我在命名空间中定义了几个函数和字段。其中一个函数将初始化字段,然后在对 std::async 的调用中运行另一个函数。调用的函数应无限期运行,直到标记为停止,最常见的是从其自己的线程外部。基本代码如下所示

namespace Game
{
void Create() {
Initialize();
auto returned = std::async(RunGameLoop, std::ref(FLAGS));
}
}

现在,我尝试实现这一点的方法是在命名空间中初始化这些标志:

namespace Game
{
namespace // This is used because the fields and functions here should be for internal use only
{
bool stopped = false;
}
}

在 RunGameLoop 函数中,基本结构设置如下

namespace Game
{
namespace // This is used because the fields and functions here should be for internal use only
{
void RunGameLoop()
{
while (!stopped)
{
// ... do stuff
}
}
}
}

但似乎由于异步的工作方式,如果我从 RunGameLoop 函数内部以外的任何地方更改stopped的值,RunGameLoop 函数看不到任何变化。大概在创建异步函数调用时,C++只是在构造时复制范围内的所有值,按值而不是引用传递它们。

我的问题是:如何在异步函数循环中使此更改明显?甚至更好:有没有更好的方法来用C++中的异步函数来传达像这样的简单全局标志?我已经尝试过使用 std::ref、传递指针和通过引用传递整个标志映射,但似乎在 RunGameLoop 函数之外所做的任何更改在 RunGameLoop 函数中都不会明显。

编辑:我已经设法在一个最小的示例中复制了这个问题,该程序将无限期运行,并且实际上永远不会达到第二个std::cout语句,这是违反直觉的。事实上,std::async 调用似乎根本没有异步运行该函数,这比我在自己的项目中遇到的要苛刻一些。我承认我可能误解了应该如何使用 std::async,但似乎这段代码应该对我有用。

编辑2:我搞砸了我之前的例子,所以我修复了它。不幸的是,现在它似乎按预期运行,与我的实际项目不同:

#include <iostream>
#include <future>
namespace test
{
namespace
{
std::atomic<bool> testbool = false;
std::future<void> returned;
void queryTestBool()
{
while (!testbool)
{
}
std::cout << "EXITED THREAD: " << std::boolalpha << testbool << std::endl;
}
}
void Initialize()
{
testbool = false;
}
void Delete()
{
testbool = !testbool;
returned.get();
}
void Create()
{
Initialize();
returned = std::async(queryTestBool);
}
}
int main()
{
using namespace test;
std::cout << std::boolalpha << testbool << std::endl;
Create();
Delete();
std::cout << std::boolalpha << testbool << std::endl;
}

此程序输出

false

EXITED THREAD: true

true

这意味着 Delete 函数不仅成功地更改了testbool的值,而且在异步 while 循环中注意到了这种变化。由于某种原因,最后一部分是我自己的项目中没有发生的事情,即使我使用 std::atomic。我会进一步调查。

所以我觉得自己非常愚蠢。在为此苦苦挣扎了数周,实现了各种东西之后,我终于发现我的测试称为 Delete(( 函数的地方被跳过了,因为一个失败的断言,我没想到在运行其余部分之前让测试退出......谜团解开

最新更新