楼主: lvzhihan

程序运行时removechild报错

[复制链接]

该用户从未签到

发表于 2009-11-10 12:00:11 | 显示全部楼层
没有,建议这类操作都使用回调来完成;至少在我这里不会因此受到什么限制

该用户从未签到

发表于 2009-11-10 20:34:10 | 显示全部楼层
本帖最后由 口口广大 于 2009-11-10 20:38 编辑

这个问题我这几天也碰到,而且折腾了我好几天,同样在MFC下,自己建立个一个简单的类osgObject
//构造函数,一个group节点下,挂一个PositionAttitudeTransform节点
osgObject:sgObject(void)
{ osg::ref_ptr <osg::group> group = new osg::Group;
osg::ref_ptr <osg:ositionAttitudeTransfrom >AT= new osg::PositionAttitudeTransform;
group ->addChild(PAT.get()); }

//析构函数,group节点移除PositionAttitudeTransform节点 osgObject::~osgObject(void)
{ group ->removeChild(PAT.get()); }

在vs2005 debug模式下,osg渲染采用独立的线程,在frame()前不断的创建删除osgObject对象,没有问题。

osgObject *ob = new osgObject ();
delete ob;

但是当MFC别的线程不断地删除osgObject对象,而我的frame()不断创建新的osgObject对象时,就会发生如楼主所述的错误,引起一个断言,表示的意思是某个STL的迭代器指针错误。

我想可能是由10楼的朋友所述,线程之间产生了冲突,应该在添加删除节点线程和frame线程使用线程锁。

该用户从未签到

发表于 2009-11-11 08:23:02 | 显示全部楼层
为啥我不会遇到……我们这里是我负责编写三维代码,然后再结合到MFC界面下,一直没出过问题……也从来没用过互斥锁

该用户从未签到

 楼主| 发表于 2009-11-11 10:51:18 | 显示全部楼层
33# array

新书啥时候出?把希望寄托于此了

该用户从未签到

发表于 2009-11-11 12:12:56 | 显示全部楼层
大约12月份可能性比较大。此外书里也不会讲解这部分内容。

该用户从未签到

 楼主| 发表于 2009-11-11 14:15:03 | 显示全部楼层
35# array


能给点这问题相关的你用的代码吗?学习下

该用户从未签到

发表于 2009-11-11 14:23:13 | 显示全部楼层
抱歉我没有用过什么特别的代码,就是按部就班地setDataVariance,然后适时地在回调里addChild/removeChild而已。也很难抽出一个单独的例子~~

该用户从未签到

发表于 2009-11-16 15:44:21 | 显示全部楼层
本帖最后由 qele 于 2009-11-16 15:48 编辑

晒一个我写的一个CallBack添加删除的回调
  1.       
  2. class CAddRemoveCallBack : public osg::NodeCallback
  3. {
  4. public:
  5. CAddRemoveCallBack(OpenThreads::Mutex* mutex);
  6. virtual ~CAddRemoveCallBack(void);
  7. virtual void operator()(osg::Node* node, osg::NodeVisitor* nv);
  8. public:
  9. void AddChild( osg::Node* node );
  10. void RemoveChild( osg::Node* node );
  11. protected:
  12. OpenThreads::Mutex* _mutex;
  13. volatile BOOL _paused;
  14. protected:
  15. std::vector<osg::Node*> _vtAdding;
  16. std::vector<osg::Node*> _vtRemoving;
  17. };
复制代码

该用户从未签到

发表于 2009-11-16 15:45:07 | 显示全部楼层
本帖最后由 qele 于 2009-11-17 10:54 编辑
  1.       
  2. /////////////////////////////////////////////////////////////////////////////
  3. // class CAddRemoveCallBack implement

  4. CAddRemoveCallBack::CAddRemoveCallBack(OpenThreads::Mutex* mutex) : _mutex(mutex), _paused(FALSE)
  5. {}

  6. CAddRemoveCallBack::~CAddRemoveCallBack(void)
  7. {}

  8. void CAddRemoveCallBack:perator()(osg::Node* node, osg::NodeVisitor* nv)
  9. {
  10.    if ( _paused )
  11.    {
  12.       OpenThreads::ScopedLock<OpenThreads::Mutex> lock( *_mutex);
  13.       osg::Group* root = dynamic_cast<osg::Group*>(node);
  14.       if ( root != NULL )
  15.       {
  16.          //        remove first
  17.          for ( size_t i = 0; i < _vtRemoving.size(); ++i )
  18.          {
  19.                root->removeChild( _vtRemoving[i] );
  20.          }
  21.          _vtRemoving.clear();

  22.          //        add node
  23.          for ( size_t i = 0; i < _vtAdding.size(); ++i )
  24.          {
  25.                root->addChild( _vtAdding[i] );
  26.          }
  27.         vtAdding.clear();
  28.       }
  29.          _paused = FALSE;
  30.      }
  31. }

  32. void CAddRemoveCallBack::AddChild( osg::Node* node )
  33. {
  34.        OpenThreads::ScopedLock<OpenThreads::Mutex> lock( *_mutex);
  35.        _vtAdding.push_back( node );
  36.        _paused = TRUE;
  37. }

  38. void CAddRemoveCallBack::RemoveChild( osg::Node* node )
  39. {
  40.         OpenThreads::ScopedLock<OpenThreads::Mutex> lock( *_mutex);
  41.         _vtRemoving.push_back( node );
  42.        _paused = TRUE;
  43. }
复制代码

该用户从未签到

 楼主| 发表于 2009-11-17 09:44:32 | 显示全部楼层
root->removeChild( _vtRemoving );
               root->addChild( _vtAdding );

这两行有问题,“osg::Group::addChild”: 不能将参数 1 从“std::vector<_Ty>”转换为“osg::Node *”

该用户从未签到

 楼主| 发表于 2009-11-17 09:44:54 | 显示全部楼层
本帖最后由 lvzhihan 于 2009-11-17 10:32 编辑

39# qele
给个用法实例

该用户从未签到

发表于 2009-11-17 10:54:52 | 显示全部楼层
40# lvzhihan
编辑错误,已修改

该用户从未签到

发表于 2009-11-17 10:59:25 | 显示全部楼层
本帖最后由 qele 于 2009-11-17 11:00 编辑

41# lvzhihan

osg::Group* root = new osg::Group;

osg::ref_ptr<CAddRemoveCallBack> addRemoveManage = new CAddRemoveCallBack(&s_Mutex);

root->addUpdateCallback( addRemoveManage.get() );

...

addRemoveManage->AddChild( node );

该用户从未签到

 楼主| 发表于 2009-11-17 11:16:17 | 显示全部楼层
&s_Mutex
这个锁为什么要作为参数?都怎么用这个?

该用户从未签到

发表于 2009-11-17 14:08:05 | 显示全部楼层
operator()是在仿真循环里运行。而add函数和仿真循环不在一个线程,加一个锁为了安全。
可以在frame所在的cpp中写一个全局OpenThreads::Mutex,初始化CAddRemoveCallBack将其加入。另外在仿真循环frame()前也加一个lock(哈哈,是不是有损效率啊?)

该用户从未签到

发表于 2009-11-17 14:18:10 | 显示全部楼层
损失了不少效率……或者说,多线程的渲染恐怕在您这里失效了

该用户从未签到

 楼主| 发表于 2009-11-17 15:04:28 | 显示全部楼层
46# array
如果线程模型本来就设置为single是不是不会影响效率了

该用户从未签到

 楼主| 发表于 2009-11-17 15:11:25 | 显示全部楼层
OpenThreads::Mutex* _mutex;
放到最外层循环了,可是运行的时候总会报错,_mutex里面全是问号。

该用户从未签到

发表于 2009-11-17 20:56:37 | 显示全部楼层
47# lvzhihan

那本身就不是多线程渲染啊~~

该用户从未签到

 楼主| 发表于 2009-11-17 21:07:02 | 显示全部楼层
49# array
我记得你在mfc+osg解决方案中提到:为了不跟mfc的线程冲突,把osg的渲染线程模型改为单线程。

该用户从未签到

 楼主| 发表于 2009-11-18 10:58:01 | 显示全部楼层
45# qele
写一个全局的OpenThreads::Mutex,
就是OpenThreads::Mutex* _mutex;这样可以吗?好像osg example里面都这样用的,但是我这样写在程序里面_mutex总是乱的。

还有,好像CAddRemoveCallBack:perator()里面的代码一直没运行到。

该用户从未签到

发表于 2009-11-18 13:12:55 | 显示全部楼层
本帖最后由 qele 于 2009-11-18 13:15 编辑

不是全局的指针。而是全局对象OpenThreads::Mutex  s_mutex;
思路是,把回调添加到场景节点,然后用此回调对象添加删除其对应节点的子节点。43楼有示例。
如果有更好的方法,欢迎大家指出~

该用户从未签到

 楼主| 发表于 2009-11-18 19:30:00 | 显示全部楼层
46# array
array把你的代码贴出来学习下吧

该用户从未签到

 楼主| 发表于 2009-11-18 19:51:35 | 显示全部楼层
52# qele

我的场景图是这样子的:rootnode->storagetree->effectgroup->graphicgroup->selection->openmodel

将rootnode装入场景:

m_Viewer->setSceneData(rootnode);
m_Viewer ->realize() ;


graphicsGroup里就是场景中所有的数据,给graphicsGroup加上回调:
graphicsGroup->addUpdateCallback(AddRemoveCallBack.get() );

现在要清空场景更换数据的时候,需要把graphicsGroup里的孩子都删除。
for(size_t i = 0; i < graphicsGroup->getNumChildren(); ++i)
{
  AddRemoveCallBack->RemoveChild(graphicsGroup->getChild(i));
}


这样子下来没有执行到CAddRemoveCallBack:perator()

我也尝试过直接给rootnode加上回调:
rootnode->addUpdateCallback(AddRemoveCallBack.get() );
但是这样子好像rootnode用RemoveChild删除不掉graphicsGroup,也就是RemoveChild不能删除孙子。

这种情况遇到过吗?

该用户从未签到

发表于 2009-11-19 09:43:00 | 显示全部楼层
节点更新回调不遍历?除非节点setNodeMask(0)停止遍历了;我这儿回调正常

该用户从未签到

 楼主| 发表于 2009-11-19 16:44:43 | 显示全部楼层
你给的例子是把场景图的根节点放到setSceneData中,并且从根节点删除孩子:
osg::Group* root = new osg::Group;
osg::ref_ptr<CAddRemoveCallBack> addRemoveManage = new CAddRemoveCallBack(&s_Mutex);
root->addUpdateCallback( addRemoveManage.get() );
m_Viewer->setSceneData(root);
m_Viewer ->realize() ;

...

addRemoveManage->AddChild( node );


现在场景图的根节点setSceneData,而对子节点添加回调,回调是否可以执行?

该用户从未签到

发表于 2009-11-20 09:44:39 | 显示全部楼层
每个节点只要添加了更新回调,应该都在updateTraversal被遍历执行。Drawable类回调有所不同,必须实现UpdateCallback::update()函数。
你查一下为什么节点回调未被运行啊

该用户从未签到

发表于 2010-1-14 19:15:58 | 显示全部楼层
小弟也遇到删除错误问题!受教了……

该用户从未签到

发表于 2010-1-14 21:22:29 | 显示全部楼层
56# lvzhihan
你的问题解决没有啊?我按照qele的方法,只有第一次能执行到回调里面以外,接下来再循环就是执行不到……很纳闷……
您需要登录后才可以回帖 登录 | 注册

本版积分规则

OSG中国官方论坛-有您OSG在中国才更好

网站简介:osgChina是国内首个三维相关技术开源社区,旨在为国内更多的技术开发人员提供最前沿的技术资讯,为更多的三维从业者提供一个学习、交流的技术平台。

联系我们

  • 工作时间:09:00--18:00
  • 反馈邮箱:1315785073@qq.com
快速回复 返回顶部 返回列表