当在MSVC的Debug模式下分配给std::future时崩溃

6
以下代码在使用MSVC编译器的Debug模式下,与Release模式不同,会在随机时间崩溃。
#include <future>

using namespace std;

int main() {
    auto l = [](){};
    auto f = async(launch::async, l);

    for (int i = 0; i < 1000000; ++i)
        f = async(launch::async, l);
}

控制台输出如下:
f:\dd\vctools\crt\crtw32\stdcpp\thr\mutex.c(51): mutex destroyed while busy
完整的调用堆栈是: https://pastebin.com/0g2ZF5C1 显然这只是一个压力测试,但我是否做了什么非常愚蠢的事情? 在我看来,将新任务分配给现有的future是可以的,因为它说operator=
释放任何共享状态并将其他内容移动分配给*this
(由于http://en.cppreference.com/w/cpp/thread/future/operator%3D)。
这是MSVC运行时中的错误吗?
值得注意的是,在赋值之前手动调用wait(),程序停止崩溃,从而使循环变成:
for (int i = 0; i < 1000000; ++i) {
    f.wait();
    f = async(launch::async, l);
}

“operator=”本身应该调用“wait”,对吗?

背景:

_MSC_VER等于1911

代码构建时使用了以下帮助:

Microsoft Visual Studio Community 2017 Preview(2)
Version 15.4.0 Preview 2.0

刚刚打开了一个全新的 C++ 项目。

@Yakk 当然,我已经编辑了这个问题。 - Pythagoras of Samos
@JoergS 这是一个合理的解释,但是即使 lambda 函数休眠了随机持续时间,我也无法让 Release 崩溃。 - Pythagoras of Samos
在 Visual Studio 2017 的非预览版本中是否会发生这种情况?例如 15.3.4。 - rustyx
@RustyX 同样的结果。 - Pythagoras of Samos
操作符=本身不应该调用wait吗?你为什么这么认为? - user2672107
显示剩余3条评论
2个回答

1

难道operator=本身不应该调用wait吗?

我不知道它是否应该,但是对MSVC15.3.4的<future>实现进行粗略查看似乎强烈暗示它不会。

//User Code
future f = /*...*/;
f = /*...*/; //(1)
//MSVC Code
future& operator=(future&& _Right) _NOEXCEPT //(1)
    {   // assign from rvalue future object
    _Mybase::operator=(_STD move(_Right)); //(2)
    return (*this);
    }
_State_manager& operator=(_State_manager&& _Other) //(2)
    {   // assign from rvalue _Other
    _Move_from(_Other); //(3)
    return (*this);
    }
void _Move_from(_State_manager& _Other) //(3)
    {   // move stored associated asynchronous state object from _Other
    if (this != _STD addressof(_Other))
        {   // different, move
        if (_Assoc_state)
            _Assoc_state->_Release(); //(4)
        _Assoc_state = _Other._Assoc_state;
        _Other._Assoc_state = 0;
        _Get_only_once = _Other._Get_only_once;
        }
    }
void _Release() //(4)
    {   // decrement reference count and destroy when zero
    if (_MT_DECR(_Refs) == 0)
        _Delete_this(); //(5)
    }
void _Delete_this() //(5)
    {   // delete this object
    if (_Deleter)
        _Deleter->_Delete(this); //External Code
    else
        delete this;
    }

既然调用wait可以帮助同步事物并确保future对象处于安全状态以进行修改,那么包括wait语句可能会更好。


0
我遇到了与 MSVC 调试模式非常相似的问题,会出现间歇性崩溃并显示“互斥锁在忙时被销毁”的消息,于是我来到了这个问题。
在我的情况下,问题实际上是 VS2017 的问题,一直存在到版本 15.8(如 此处 所述)。
升级到 VS2019 解决了我的问题。虽然这个问题已经很旧了,但我写下这篇文章作为另一种替代答案。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接