2016-08-24 102 views
3

我使用VS2015,并且在使用std :: thread时遇到了一个非常奇怪的问题。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(); 

它运作良好,在调试模式,而是抛出一个“访问冲突异常”当我打开来释放模式。

更重要的是,如果我尝试修改 “MYFUNC” 这样的:

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

一遍效果很好。

我保证“& Klass :: myfunc”和“this”指针不为NULL。当ctor被呼叫时,在几行后有一个“加入”。

我想这可能是某种“未定义的行为”,但我不知道它到底是什么。

调用堆栈是这样的:

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 
+6

你做线程后会发生什么?你会加入吗? – doctorlove

+3

@doctorlove可能暗示的是,这看起来像一个生命期问题,其中线程超过了Klass实例,因此有一个悬空的指针。通过加入正确的地方,你可以防止这一点。然而,我们无法确定基于所呈现的情况。 – stefaanv

+0

@doctorlove stefaanv嗨,谢谢你的回复。实际上,调试器和日志显示程序在调用std :: thread的ctor后立即停止,并且“join”之后是几行。我认为问题不在于“加入”。而且我在这个问题中还提到,如果我不带任何参数地称呼“myfunc”,那么一切都会顺利。 – Wizmann

回答

1

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

//... details omitted... 

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

安东尼威廉的穿线blog经过这个详细。用一个例子非常相似,你的第二个:

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

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

他说

如果你编译并运行这个小应用程序时,会发生什么?是否 打印你好我们想要的?那么,实际上没有说服力。它可能会做,也可能不会。我在我的机器上多次运行这个简单的应用程序 ,并且输出不可靠:有时它输出 “hello”,换行符;有时它会在没有 换行符的情况下输出“hello”,有时它不输出任何内容。那是怎么回事? 这样一个简单的应用程序当然应该表现可预测?

随后,他介绍了一种用join正如我上面做的想法,并说,

的问题是我们没有等待我们的线程来完成。当 执行到达main()的末尾时,程序终止, 无论其他线程在做什么。

相关问题