有一个使用std::future
和std::async
异步运行的成员函数。在某些情况下,我需要取消它。 (该函数连续加载对象附近,有时加载时对象超出范围。)我已经阅读this question解决相同问题的答案,但我无法正常工作。
这是简化的代码,其结构与我的实际程序相同。在异步运行时调用Start()
和Kill()
会因input
的访问冲突而导致崩溃。
在我看来,代码应该如下工作。调用Kill()
时,将禁用运行标志。下一个命令get()
应该等待线程结束,它会很快检查运行标志。线程取消后,input
指针将被删除。
#include <vector>
#include <future>
using namespace std;
class Class
{
future<void> task;
bool running;
int *input;
vector<int> output;
void Function()
{
for(int i = 0; i < *input; ++i)
{
if(!running) return;
output.push_back(i);
}
}
void Start()
{
input = new int(42534);
running = true;
task = async(launch::async, &Class::Function, this);
}
void Kill()
{
running = false;
task.get();
delete input;
}
};
似乎线程没有注意到将正在运行的标志切换为false。我的错是什么?
答案 0 :(得分:8)
由于没有人真正回答了这个问题,我会这样做。
对running
变量的写入和读取不是原子操作,因此代码中没有任何内容导致两个线程之间的任何同步,因此没有任何东西可以确保异步线程看到变量已更改
可能发生的一种可能方式是编译器分析Function
的代码,确定该线程中的变量永远不会有任何写入,并且因为它不是其他线程写入的原子对象要求可见,因此将代码重新排列为完全合法:
void Function()
{
if(!running) return;
for(int i = 0; i < *input; ++i)
{
output.push_back(i);
}
}
显然,在此代码中,如果running
在函数启动后发生更改,则不会导致循环停止。
C ++标准允许您同步两个线程有两种方法,即使用互斥锁,只在互斥锁被锁定时读取或写入running
变量,或者使变量成为原子变量。在您的情况下,将running
从bool
更改为atomic<bool>
将确保对变量的写入与其读取同步,并且异步线程将终止。