我正在尝试使用atomic_bool来打破std :: async,代码的结构如下所示
class Test
{
atomic_bool IsStopped;
std::future <void> Future;
Test ()
: IsStopped (false);
{
LogValueWithMutex (IsStopped);
Future = std::async (std::launch::async, &Test::AsyncFunction, this);
}
~Test ()
{
LogValueWithMutex (IsStopped);
IsStopped = true;
if (Future.valid ())
Future.get ();
}
void AsyncFunction ()
{
while (1)
{
// only read atomic_bool, does not write
if (IsStopped)
break;
}
}
void CallbackFromNetworkWhichIsNotImportant ()
{
// Bug here!! On 2nd entry, this value is set to true! In Both Debug/Release Mode
LogValueWithMutex (IsStopped);
if (! IsStopped)
{
IsStopped = true;
if (Future.valid ())
Future.get ();
// call an API which exit and will destroy this class
}
}
}
一切正常,异步可以正常破坏。但是,在VS2015中第2次创建类时,CallbackFromNetworkWhichIsNotImportant中的LogValueWithMutex为true。我已经验证了它的日志输出
Test ctor IsStopped: 0
Test CallbackFromNetworkWhichIsNotImportant: 0
Test dtor IsStopped: 1
Test ctor IsStopped: 0
Test CallbackFromNetworkWhichIsNotImportant: 1 <- Wrong! Who is setting this to true??!!
Test dtor IsStopped: 1
IsStopped仅在dtor和CallbackFromNetworkWhichIsNotImportant中指定为true。
所以我试着检查它是否是一个实例问题,我添加了一个新的随机变量,然后它神奇地起作用了!
class Test
{
atomic_bool IsStopped;
std::future <void> Future;
std::string RandomString; // HERE IS A TEST
Test ()
: IsStopped (false);
{
// NEW CODE
ostringstream oss;
oss << rand ()% 100;
RandomStringToTestInstance = oss.str ();
LogValueWithMutex (IsStopped);
Future = std::async (std::launch::async, &Test::AsyncFunction, this);
}
// all parts unchanged
}
Test ctor IsStopped: 0
Test CallbackFromNetworkWhichIsNotImportant: 0
Test dtor IsStopped: 1
Test ctor IsStopped: 0
Test CallbackFromNetworkWhichIsNotImportant: 0 <- Correct!!
Test dtor IsStopped: 1
我的理解是atomic_bool不需要volatile,但不知何故它看起来像是。是否有某种优化或某些自动生成的移动操作符可能导致这种情况?
答案 0 :(得分:1)
缺少代码的使用。但是我相信那里有一些多线程。多线程很棘手,很容易进入 &#39;竞争条件&#39> ,即事物顺序很重要的情况,在某些情况下可能不会预期
为了调查您的故事,我创建了一个简单的用法,可以重现您的意外输出。它不一定与您在下面创建的场景完全相同,可能还有其他类似的竞争条件。再现您的意外输出的代码是BAD(该对象在一个线程中被删除,同时仍在另一个线程中使用)但是这样的错误可能发生在多线程程序中。在代码中查找这样的错误...(除非您对 RandomString 解决方案感到满意: - )
case 1:
Test::Test(): IsStopped = 0
void Test::CallbackFromNetworkWhichIsNotImportant(): IsStopped = 0
Test::~Test(): IsStopped = 1
case 2:
Test::Test(): IsStopped = 0
void Test::CallbackFromNetworkWhichIsNotImportant(): IsStopped = 1
Test::~Test(): IsStopped = 1
int main() {
// OK scenario
{
cout << "case 1:" << endl;
Test t;
t.CallbackFromNetworkWhichIsNotImportant();
}
// Bad scenario
std::this_thread::sleep_for(1s);
cout << "case 2:" << endl;
Test* tp = new Test();
// here the error is quite verbose, but the same can be more hidden in the code
std::thread th(&Test::CallbackFromNetworkWhichIsNotImportant, std::ref(*tp));
delete tp;
th.join();
}
代码: http://coliru.stacked-crooked.com/a/b8c0028766bcfc5c
另请注意,您的CallbackFromNetworkWhichIsNotImportant
功能在某些时候可以说:
// call an API which exit and will destroy this class
可能是对象在两个不同的地方被摧毁了两次。
答案 1 :(得分:0)
我发现了问题。这与async或atomic_bool无关(我第一次尝试)。我正在基于“this”分配一个回调但是只做了一次,所以当我再次启动该类时,它正在使用现有实例(因此损坏的内存)。使用atomic_bool打破循环的多线程工作正常。抱歉误报。