使用参数创建时,std::thread 抛出访问冲突异常? [关闭]
Posted
技术标签:
【中文标题】使用参数创建时,std::thread 抛出访问冲突异常? [关闭]【英文标题】:std::thread throws Access violation exception when created with arguments? [closed] 【发布时间】:2016-08-24 13:34:46 【问题描述】:我用的是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();
它在 Debug 模式下运行良好,但在我切换到 Release 模式时会引发“访问冲突异常”。
此外,如果我尝试将“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时,在几行之后有一个“join”。
我猜这可能是某种“未定义的行为”,但我不知道它到底是什么。
调用栈是这样的:
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
【问题讨论】:
创建线程后会发生什么?你join
了吗?
@doctorlove 可能暗示的是,这看起来像是一个生命周期问题,其中线程比 Klass 实例寿命更长,因此有一个悬空的 this 指针。通过在正确的位置加入,您可以防止这种情况发生。但是,根据所提供的背景,我们无法确定。
@doctorlove stefaanv 两位您好,感谢您的回复。实际上,调试器和日志显示程序在调用 std::thread 的 ctor 后立即关闭,并且“join”在几行之后。我认为问题不在于“加入”。而且我在问题中也提到,如果我不带参数调用“myfunc”,一切都会顺利。
请编辑您的问题以包含minimal reproducible example
【参考方案1】:
您应该始终确保加入(或可能分离)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);
他说
如果您编译并运行这个小应用程序,会发生什么?可以 像我们想要的那样打印你好?嗯,其实也没什么好说的。它 可能会,也可能不会。我多次运行这个简单的应用程序 在我的机器上,输出不可靠:有时它输出 “你好”,带有换行符;有时它会输出“hello”而没有 换行,有时它没有输出任何东西。那是怎么回事? 像这样一个简单的应用程序肯定应该可以预测吗?
然后他介绍了使用join
的想法,就像我在上面所做的那样,并说,
问题是我们没有等待我们的线程完成。当。。。的时候 执行到 main() 程序结束,程序终止, 无论其他线程在做什么。
【讨论】:
以上是关于使用参数创建时,std::thread 抛出访问冲突异常? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
std::thread创建线程,使用std::ref()传递类对象参数
std::thread创建线程,使用std::ref()传递类对象参数