使用 VS2012 RC 时,如果在 main() 退出后调用 std::thread::join() 会挂起

std::thread::join() hangs if called after main() exits when using VS2012 RC(使用 VS2012 RC 时,如果在 main() 退出后调用 std::thread::join() 会挂起)

本文介绍了使用 VS2012 RC 时,如果在 main() 退出后调用 std::thread::join() 会挂起的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

以下示例在 Ubuntu 12.04 上使用 Clang 3.2 或 GCC 4.7 编译时成功运行(即不会挂起),但如果我使用 VS11 Beta 或 VS2012 RC 编译则挂起.

The following example runs successfully (i.e. doesn't hang) if compiled using Clang 3.2 or GCC 4.7 on Ubuntu 12.04, but hangs if I compile using VS11 Beta or VS2012 RC.

#include <iostream>
#include <string>
#include <thread>
#include "boost/thread/thread.hpp"

void SleepFor(int ms) {
  std::this_thread::sleep_for(std::chrono::milliseconds(ms));
}

template<typename T>
class ThreadTest {
 public:
  ThreadTest() : thread_([] { SleepFor(10); }) {}
  ~ThreadTest() {
    std::cout << "About to join	" << id() << '
';
    thread_.join();
    std::cout << "Joined		" << id() << '
';
  }
 private:
  std::string id() const { return typeid(decltype(thread_)).name(); }
  T thread_;
};

int main() {
  static ThreadTest<std::thread> std_test;
  static ThreadTest<boost::thread> boost_test;
//  SleepFor(100);
}

问题似乎是 std::thread::join() 如果在 main 退出后调用它就永远不会返回.它在 cthread.c 中定义的 _Thrd_join 中的 WaitForSingleObject 处被阻塞.

The issue appears to be that std::thread::join() never returns if it is invoked after main has exited. It is blocked at WaitForSingleObject in _Thrd_join defined in cthread.c.

取消注释 SleepFor(100);main 的末尾允许程序正确退出,就像使 std_test 非静态一样.使用 boost::thread 也可以避免这个问题.

Uncommenting SleepFor(100); at the end of main allows the program to exit properly, as does making std_test non-static. Using boost::thread also avoids the issue.

所以我想知道我是否在这里调用了未定义的行为(在我看来不太可能),或者我是否应该针对 VS2012 提交错误?

So I'd like to know if I'm invoking undefined behaviour here (seems unlikely to me), or if I should be filing a bug against VS2012?

推荐答案

追踪 Fraser 在他的连接错误中的示例代码 (https://connect.microsoft.com/VisualStudio/feedback/details/747145)VS2012 RTM 似乎显示了一个相当简单的死锁情况.这可能不是 std::thread 特有的 - 很可能 _beginthreadex 遭受同样的命运.

Tracing through Fraser's sample code in his connect bug (https://connect.microsoft.com/VisualStudio/feedback/details/747145) with VS2012 RTM seems to show a fairly straightforward case of deadlocking. This likely isn't specific to std::thread - likely _beginthreadex suffers the same fate.

我在调试器中看到的内容如下:

What I see in the debugger is the following:

在主线程上,main()函数已经完成,进程清理代码获得了一个名为_EXIT_LOCK1的临界区,称为ThreadTest的析构函数,并且正在(无限期地)等待第二个线程退出(通过调用 join()).

On the main thread, the main() function has completed, the process cleanup code has acquired a critical section called _EXIT_LOCK1, called the destructor of ThreadTest, and is waiting (indefinitely) on the second thread to exit (via the call to join()).

第二个线程的匿名函数已完成,正在线程清理代码中等待获取_EXIT_LOCK1 临界区.不幸的是,由于时间问题(第二个线程的匿名函数的生命周期超过了 main() 函数的生命周期),主线程已经拥有该临界区.

The second thread's anonymous function completed and is in the thread cleanup code waiting to acquire the _EXIT_LOCK1 critical section. Unfortunately, due to the timing of things (whereby the second thread's anonymous function's lifetime exceeds that of the main() function) the main thread already owns that critical section.

死锁.

任何延长main()生命周期的东西,这样第二个线程就可以在主线程避免死锁情况之前获取_EXIT_LOCK1.这就是为什么取消注释 main() 中的 sleep 会导致干净关闭.

Anything that extends the lifetime of main() such that the second thread can acquire _EXIT_LOCK1 before the main thread avoids the deadlock situation. That's why the uncommenting the sleep in main() results in a clean shutdown.

或者,如果您从 ThreadTest 局部变量中删除 static 关键字,则析构函数调用将向上移动到 main() 函数的末尾(而不是在进程清理代码)然后阻塞直到第二个线程退出 - 避免死锁情况.

Alternatively if you remove the static keyword from the ThreadTest local variable, the destructor call is moved up to the end of the main() function (instead of in the process cleanup code) which then blocks until the second thread has exited - avoiding the deadlock situation.

或者您可以向 ThreadTest 添加一个函数,该函数调用 join() 并在 main() 的末尾调用该函数 - 再次避免死锁情况.

Or you could add a function to ThreadTest that calls join() and call that function at the end of main() - again avoiding the deadlock situation.

这篇关于使用 VS2012 RC 时,如果在 main() 退出后调用 std::thread::join() 会挂起的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!

本文标题为:使用 VS2012 RC 时,如果在 main() 退出后调用 std::thread::join() 会挂起

基础教程推荐