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

问题描述

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

  #include< iostream> 
#include< string>
#include< thread>
#includeboost / thread / thread.hpp

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

template< typename T>
类ThreadTest {
public:
ThreadTest():thread _([] {SleepFor(10);}){}
〜ThreadTest(){
std: :cout< 关于加入\t< id()<< '\\\
';
thread_.join();
std :: cout<< Joined\t\t<< id()<< '\\\
';
}
private:
std :: string id()const {return typeid(decltype(thread _))。 }
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 处被阻止。
$ b

取消注释 SleepFor(100); main 结束时允许程序正常退出使 std_test 非静态。使用 boost :: thread 也避免了这个问题。



所以我想知道如果我调用

解决方案

通过Fraser的示例进行跟踪代码( https://connect.microsoft.com/VisualStudio/feedback/details/747145)与VS2012 RTM似乎显示了一个相当简单的死锁情况。这可能不是特定于 std :: thread - 可能 _beginthreadex 遭受同样的命运。



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



在主线程上, main 函数已完成,进程清理代码已获取称为 _EXIT_LOCK1 的关键部分,称为 ThreadTest ,并且在第二个线程上等待(无限期地)退出(通过调用 join())。



第二个线程的匿名函数完成,并在线程清理代码等待获取 _EXIT_LOCK1 临界区。不幸的是,由于事情的时间(第二线程的匿名函数的生命周期超过了 main()函数),主线程已经拥有该关键部分。



DEADLOCK。



任何延长 main ),使得第二个线程可以在主线程避免死锁情况之前获取 _EXIT_LOCK1 。这就是为什么在 main()中取消注释会导致一个干净的关闭。



ThreadTest 局部变量的关键字中,析构函数调用被移动到 main()



或者你可以在中添加一个函数,调用 join()并在 main()结束时调用该函数的ThreadTest - 再次避免了死锁情况。


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\t" << id() << '\n';
    thread_.join();
    std::cout << "Joined\t\t" << id() << '\n';
  }
 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);
}

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.

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.

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?

解决方案

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:

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()).

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.

DEADLOCK.

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.

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.

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.

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

11-02 16:12