std :: thread在使用参数创建时抛出访问冲突异常?

时间:2016-08-24 13:34:46

标签: c++ multithreading c++11 stdthread

我使用VS2015并在使用std :: thread时遇到一个非常奇怪的问题。

void Klass::myfunc(int a, int b) { std::cout << a << ' ' << b << std::endl; }
// ...
auto t = std::thread(&Klass::myfunc, this, 100, 200); <- runtime error after called
// ...
t.join();

它在调试模式下运行良好,但会引发&#34;访问冲突异常&#34;当我转向发布模式时。

还有什么,如果我尝试修改&#34; myfunc&#34;对此:

void Klass::myfunc() { std::cout << "foo" << std::endl; }
// ...
auto t = std::thread(&Klass::myfunc, this); // everything goes well
// ...
t.join();

再次运作良好。

我保证&#34;&amp; Klass :: myfunc&#34;和&#34;这个&#34;指针不是NULL。还有一个&#34;加入&#34;在调用ctor之后的几行之后。

我想这可能是某种&#34;未定义的行为&#34;但我不知道究竟是什么。

调用堆栈是这样的:

    000000c83a4ffd40()  Unknown
>   distributed_word_embedding.exe!std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl multiverso::Communicator::*)(void) __ptr64,multiverso::Communicator * __ptr64>,std::default_delete<std::tuple<void (__cdecl multiverso::Communicator::*)(void) __ptr64,multiverso::Communicator * __ptr64> > > >::_Run(std::_LaunchPad<std::unique_ptr<std::tuple<void (__cdecl multiverso::Communicator::*)(void),multiverso::Communicator *>,std::default_delete<std::tuple<void (__cdecl multiverso::Communicator::*)(void),multiverso::Communicator *> > > > * _Ln) Line 247    C++
    distributed_word_embedding.exe!std::_Pad::_Call_func(void * _Data) Line 210 C++
    ucrtbase.dll!00007ffabdc7be1d() Unknown
    kernel32.dll!00007ffabfae8102() Unknown
    ntdll.dll!00007ffac26bc5b4()    Unknown

1 个答案:

答案 0 :(得分:0)

您应该始终确保加入(或可能分离)thread,否则main尤其是使用对象的线程(在这种情况下为this)将会(有时)导致问题。

//... details omitted...

int main()
{
  auto t = std::thread(&Klass::myfunc, this);
  t.join();  //<----- NOTE THIS
}

Anthony William的线程blog详细介绍了这一点。举个例子与你的第二个非常相似:

void my_thread_func()
{
    std::cout<<"hello"<<std::endl;
}

int main()
{
    std::thread t(my_thread_func);
}

他说

  

如果您编译并运行这个小应用程序,会发生什么?可以   打印你好我们想要的?嗯,实际上没有任何说服力。它   可能会或不会。我多次运行这个简单的应用程序   在我的机器上,输出不可靠:有时输出   “你好”,带换行符;有时它输出“你好”没有   换行,有时它没有输出任何东西。那是怎么回事?   当然这样一个简单的应用程序应该可预测吗?

然后,他介绍了如上所述使用join的想法,然后说,

  

问题是我们不是在等待我们的线程完成。当。。。的时候   执行到达main()结束程序终止,   无论其他线程在做什么。