C++ 异步竞争条件还是错误?
我试图使用atomic_bool打破std::async,代码结构如下所示C++ 异步竞争条件还是错误?,c++,asynchronous,std,C++,Asynchronous,Std,我试图使用atomic_bool打破std::async,代码结构如下所示 class Test { atomic_bool IsStopped; std::future <void> Future; Test () : IsStopped (false); { LogValueWithMutex (IsStopped); Future = std::async (std::launch::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
}
}
}
类测试
{
原子布尔;
std:未来;
测试()
:i(假);
{
具有互斥的LogValueWithMutex(IsStopped);
Future=std::async(std::launch::async,&Test::async函数,this);
}
~Test()
{
具有互斥的LogValueWithMutex(IsStopped);
IsStopped=true;
if(Future.valid())
Future.get();
}
void异步函数()
{
而(1)
{
//只读原子布尔,不写
如有(见附件)
打破
}
}
无效从不重要的网络调用()
{
//这里有Bug!!在第二个条目中,这个值被设置为true!在调试/发布模式下
具有互斥的LogValueWithMutex(IsStopped);
如果(!IsStopped)
{
IsStopped=true;
if(Future.valid())
Future.get();
//调用退出并将销毁此类的API
}
}
}
只要异步能正常中断,一切都能正常工作。然而,在VS2015中第二次创建该类时,从Network调用LogValueWithMutex,这并不重要。我已经验证了它的日志输出
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
测试:0
来自网络的测试调用,该调用不重要:0
测试数据类型:1
测试时间:0
来自网络的测试调用不重要:1缺少代码的用法。然而,我相信有一些多线程正在那里进行。多线程处理很棘手,很容易陷入“竞争条件”,即事情的顺序很重要,在某些情况下可能变得不符合预期
为了调查您的故事,我创建了一个简单的用法,可以重现您意外的输出。你不一定会有和我在下面创建的完全相同的场景,可能会有其他类似的比赛条件。复制意外输出的代码是错误的(对象在一个线程中被删除,而在另一个线程中仍在使用),但类似的错误可能会发生在多线程程序中。在你的代码中寻找这样一个bug。。。(除非您对随机字符串解决方案满意:-)
以下是我得到的输出:
主要有以下几点:
可能是该对象从两个不同的地方被销毁了两次。我发现了问题。这与异步或原子布尔无关(这是我第一次尝试)。我根据“this”分配了一个回调,但只执行了一次,所以当我再次新建该类时,它正在现有实例上使用(因此内存已损坏)。使用原子布尔来打破循环的多线程处理工作得很好。很抱歉出现了误报。我没有理解问题的地方是启动测试类的代码。我正在使用cocos2dx,它是一个状态机,用于处理应用程序状态,类似于此,它将管理新建/删除并选择要运行的状态(类)。我在状态之间切换。变量中的一个值从未设置,然后插入另一个变量,然后它突然工作。。。这种行为的原因通常是越界访问或写入野生指针,或写入调用中遗漏的参数。(好的,如果你没有疯狂函数指针的转换,那么C++中就不应该发生后者。)
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
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();
}
// call an API which exit and will destroy this class