boost 1.55库,使用thread,为何出现以下怪现象?请大牛来指点!!

雨中的月儿 2013-12-12 11:35:14
直接上代码:

#include <boost/thread.hpp>
#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/smart_ptr.hpp>
using namespace boost;

#include "EasyLog.h"
#include "Utils.h"

boost::thread g_thrd;

class MyClass : public enable_shared_from_this<MyClass>
{
public:
int ThreadProc()
{
log_debug("[%s] BEGIN ========\n", __FUNCTION__);
Utils::ThreadSleep(2000);
log_debug("[%s] END ======================\n", __FUNCTION__);

return 0;
}

MyClass()
{
log_debug("++++\t[%s]\n", __FUNCTION__);
}

~MyClass()
{
log_debug("----\t[%s]\n", __FUNCTION__);
}

void Start()
{
//g_thrd = // 奇怪的地方在这儿!!,如果不加注释,使用g_thrd进行赋值保存,就晕了。。。
boost::thread(boost::bind(&MyClass::ThreadProc, shared_from_this()));
}
};

void Test_Thread()
{
shared_ptr<MyClass> sp(new MyClass());
sp->Start();
}

void CodeWrapper()
{
Test_Thread();
}

===========================================================
上述代码在VC2008+Win7环境下,输出结果为:

23:29:22 ~173C DEBUG| ++++ [MyClass::MyClass]
23:29:22 ~1BAC DEBUG| [MyClass::ThreadProc] BEGIN ========
23:29:24 ~1BAC DEBUG| [MyClass::ThreadProc] END ======================
23:29:24 ~1BAC DEBUG| ---- [MyClass::~MyClass]
表示在子线程退出之后,MyClass正确的调用了析构函数。
==============================================================
问题在于:
1. 在MyClass::Start()中,如果使用g_thrd保存启动的子线程,子线程依然可以正确退出(在任务管理器中可以确认),但MyClass::~MyClass()就不会被调用了,也就是说,new出来的MyClass不会被析构。
即:
23:29:24 ~1BAC DEBUG| ---- [MyClass::~MyClass]
这一行,永远不会打印出来。。。。。。

请问高手,为什么我用一个全局的g_thrd去保存这个子线程的对象,子线程正确退出之后,~MyClass不会被执行呢?我在这个子线程里打印了shared<MyClass>的use_count(),值为2,表示shared_ptr对象的引用计数没有问题,那问题出在哪儿呢?

理解不了了,请高手指点!!!
...全文
271 16 打赏 收藏 转发到动态 举报
写回复
用AI写文章
16 条回复
切换为时间正序
请发表友善的回复…
发表回复
icosagon 2013-12-19
  • 打赏
  • 举报
回复
引用 14 楼 yysbest 的回复:
我调试的时候,确实看到了g_thrd里有shared_ptr<>对类对象的使用,所以就会出现循环嵌套的shared_ptr<>调用。 最后我没有使用shared_from_this(),直接使用了this,然后把这个类对象的生存周期交给了一个单独线程进行管理,在销毁对象前等待对象专属线程退出,暂时解决了这个奇葩的问题。。。
要释放g_thrd里保持的智能指针只要g_thrd.swap(thread())进行置空操作就行了,没有必要舍弃shared_from_this()。
雨中的月儿 2013-12-19
  • 打赏
  • 举报
回复
再想想zhao4zhong1的回复“无New,无Delete”,我真是无语,那么多勋章里有多少类似这种水分式的回复积累起来的?
雨中的月儿 2013-12-19
  • 打赏
  • 举报
回复
我调试的时候,确实看到了g_thrd里有shared_ptr<>对类对象的使用,所以就会出现循环嵌套的shared_ptr<>调用。 最后我没有使用shared_from_this(),直接使用了this,然后把这个类对象的生存周期交给了一个单独线程进行管理,在销毁对象前等待对象专属线程退出,暂时解决了这个奇葩的问题。。。
jiandingzhe 2013-12-17
  • 打赏
  • 举报
回复
引用 10 楼 icosagon 的回复:
[quote=引用 8 楼 u012908616 的回复:] g_thrd = boost::thread(....); 这里会调用thread的拷贝构造函数,我印象中boost并不支持C++11, 所以这里应该是一个参数为非const引用的拷贝构造函数,这样导致thread本身并没有实质性复制(右值的内容转移到左值,右值本身被清空),也就是说这句执行完成后, g_thrd 将会拥有 boost::bind(...) 的结果并阻止其被释放, 而 boost::bind(...)的结果又会保持对 shared_from_this() 的引用,也就是阻止 MyClass 的实例被释放。
这个就不用担心了,boost库会自动检测编译器是否支持右值引用,如果不支持,会使用一些变态的手法支持右值构造和右值赋值函数[/quote] 不直接支持。你需要使用boost::ref传递一个引用进去。详情见boost线程库的教程。
Todd_Pointer 2013-12-16
  • 打赏
  • 举报
回复
另外, “这里会调用thread的拷贝构造函数 .... 所以这里应该是一个参数为非const引用的拷贝构造函数”这句里的“拷贝构造函数”应该是赋值运算符
引用 11 楼 u012908616 的回复:
确实。我一直以为boost与c++11不兼容。 但似乎不影响我的结论。 [quote=引用 10 楼 icosagon 的回复:] [quote=引用 8 楼 u012908616 的回复:] g_thrd = boost::thread(....); 这里会调用thread的拷贝构造函数,我印象中boost并不支持C++11, 所以这里应该是一个参数为非const引用的拷贝构造函数,这样导致thread本身并没有实质性复制(右值的内容转移到左值,右值本身被清空),也就是说这句执行完成后, g_thrd 将会拥有 boost::bind(...) 的结果并阻止其被释放, 而 boost::bind(...)的结果又会保持对 shared_from_this() 的引用,也就是阻止 MyClass 的实例被释放。
这个就不用担心了,boost库会自动检测编译器是否支持右值引用,如果不支持,会使用一些变态的手法支持右值构造和右值赋值函数[/quote][/quote]
Todd_Pointer 2013-12-16
  • 打赏
  • 举报
回复
确实。我一直以为boost与c++11不兼容。 但似乎不影响我的结论。
引用 10 楼 icosagon 的回复:
[quote=引用 8 楼 u012908616 的回复:] g_thrd = boost::thread(....); 这里会调用thread的拷贝构造函数,我印象中boost并不支持C++11, 所以这里应该是一个参数为非const引用的拷贝构造函数,这样导致thread本身并没有实质性复制(右值的内容转移到左值,右值本身被清空),也就是说这句执行完成后, g_thrd 将会拥有 boost::bind(...) 的结果并阻止其被释放, 而 boost::bind(...)的结果又会保持对 shared_from_this() 的引用,也就是阻止 MyClass 的实例被释放。
这个就不用担心了,boost库会自动检测编译器是否支持右值引用,如果不支持,会使用一些变态的手法支持右值构造和右值赋值函数[/quote]
icosagon 2013-12-16
  • 打赏
  • 举报
回复
引用 8 楼 u012908616 的回复:
g_thrd = boost::thread(....); 这里会调用thread的拷贝构造函数,我印象中boost并不支持C++11, 所以这里应该是一个参数为非const引用的拷贝构造函数,这样导致thread本身并没有实质性复制(右值的内容转移到左值,右值本身被清空),也就是说这句执行完成后, g_thrd 将会拥有 boost::bind(...) 的结果并阻止其被释放, 而 boost::bind(...)的结果又会保持对 shared_from_this() 的引用,也就是阻止 MyClass 的实例被释放。
这个就不用担心了,boost库会自动检测编译器是否支持右值引用,如果不支持,会使用一些变态的手法支持右值构造和右值赋值函数
icosagon 2013-12-16
  • 打赏
  • 举报
回复
引用 7 楼 jiandingzhe 的回复:
shared_from_this是干啥的?光使过boost的thread,没使过这个。
主要用于在一个类的成员函数中,发起一个异步调用,因为异步回调在真正调用的时候才会使用类指针去调用函数,如果不使用shared_from_this构造出一份智能指针,在回调函数真正被调用的时候,类实际可能已经被析构了,使用智能指针保证在回调函数真正调用的时候没被析构。
Todd_Pointer 2013-12-16
  • 打赏
  • 举报
回复
g_thrd = boost::thread(....); 这里会调用thread的拷贝构造函数,我印象中boost并不支持C++11, 所以这里应该是一个参数为非const引用的拷贝构造函数,这样导致thread本身并没有实质性复制(右值的内容转移到左值,右值本身被清空),也就是说这句执行完成后, g_thrd 将会拥有 boost::bind(...) 的结果并阻止其被释放, 而 boost::bind(...)的结果又会保持对 shared_from_this() 的引用,也就是阻止 MyClass 的实例被释放。
jiandingzhe 2013-12-16
  • 打赏
  • 举报
回复
shared_from_this是干啥的?光使过boost的thread,没使过这个。
icosagon 2013-12-16
  • 打赏
  • 举报
回复
应该是shared_from_this()引起的 g_thrd这个变量一直没析构,保存着一份MyClass智能指针
雨中的月儿 2013-12-16
  • 打赏
  • 举报
回复
天老爷的,高手在哪儿呢?
雨中的月儿 2013-12-13
  • 打赏
  • 举报
回复
引用 3 楼 zhao4zhong1 的回复:
无new,无delete 有new,必须要有对应的delete
我不知道你说的是什么意思,shared_ptr的本意就是不需要手工delete了,为什么还要"必须有对应的delete"?兄弟,能不能说的再清楚一些?
赵4老师 2013-12-13
  • 打赏
  • 举报
回复
无new,无delete 有new,必须要有对应的delete
雨中的月儿 2013-12-13
  • 打赏
  • 举报
回复
继续在线等~~~~
雨中的月儿 2013-12-13
  • 打赏
  • 举报
回复
高手,高手,高手,高手。。。。。。 赶紧来啊。。。。

64,651

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧