查看: 6197|回复: 13

还是MFC下使用OSG时的多线程问题!

[复制链接]

该用户从未签到

发表于 2011-9-18 21:41:39 | 显示全部楼层 |阅读模式
基于MFC的OSG程序,基本上就是使用osgMFC例子的方式,在MainFrame里加了个全局变量,通过网络接收数据后写到这个全局变量中(大约100ms更新一次数据),在OSG中按海军教程的方法包装了一个载具类用于管理场景中的载具运动,用Drawable派生类显示航迹、雷达扫描波束等(均用openGL根据全局变量中的网络数据进行绘制),要求达到的效果是:根据全局变量中的数据实时改变载具的运动及姿态、绘制航迹、雷达扫描波束等。osg开了一个线程,网络接收数据用了一个线程,接收数据写到全局变量的时候加了互斥保护,在载具的节点回调中直接通过指针读取全局变量中的数据,也加了互斥保护,可是在程序运行时还是会出现访问冲突。把互斥保护加到mViewer->frame()前后,去掉载具节点回调中的互斥保护,还是访问冲突,把OSG改成单线程模式,问题依旧。通过Trace跟踪发现在OSG读数据时,网络线程同时在写数据,于是就出现冲突。不用网络线程,用OnTimer定时改变全局变量的值,也会出现冲突。
      请问MFC中使用OSG时像这样的多线程读写数据有什么要注意的地方吗?不知为什么,好像线程保护不了osg读数据的过程似的,程序跑一段时间后就出现访问冲突,调试两天了,没有什么进展,求助啊!!!

该用户从未签到

 楼主| 发表于 2011-9-18 22:34:35 | 显示全部楼层
我是这样进行线程保护的:

  1. WaitForSingleObject(g_pSocketManager->g_hInputQueueMutex,INFINITE);
  2. x = msgEntityMotion->fLocationX;
  3. y = msgEntityMotion->fLocationY;
  4. z = msgEntityMotion->fLocationZ;
  5. Azimuth = osg::DegreesToRadians(msgEntityMotion->fAzimuthAng);
  6. Pitch = osg::DegreesToRadians(msgEntityMotion->fPitchAng);
  7. Roll = osg::DegreesToRadians(msgEntityMotion->fRollAng);
  8. ReleaseMutex(g_pSocketManager->g_hInputQueueMutex);
复制代码

以上代码是在节点回调中取数据,其中g_pSocketManager、msgEntityMotion都是在IntegratedDisplaySystem.cpp(MFC工程名为:IntegratedDisplaySystem)中定义的全局变量。
  1. CSocketManager *g_pSocketManager=NULL;
复制代码

CSocketManager用于管理网络通信,将网络接收的数据写到msgEntityMotion全局变量中:

  1. class CSocketManager  
  2. {
  3. public:
  4. CSocketManager();
  5. virtual ~CSocketManager();
  6. private:
  7. BOOL m_bComPro;
  8. CTCPClient  m_TCPClient;
  9. HANDLE m_hDataProExitFlag;
  10. HANDLE m_hDataSendExitFlag;
  11. public:
  12. HANDLE g_hInputQueueMutex;
  13. private:
  14. static UINT WINAPI ThreadProcessComData(void *ptr);
  15. void StopThread();
  16. void StartThread();

  17. private:
  18. int ProcessMsgEntityMotion(SMsgEntityMotion MsgEntityMotion);

  19. public:
  20. bool InitTCPSocket(char *pszClientIPAddr,char *pszServerIPAddr,u_short nServerPort,u_short nLocalPort);
  21. };
复制代码

在CSocketManager:rocessMsgEntityMotion(SMsgEntityMotion MsgEntityMotion)中:

  1. ::WaitForSingleObject(g_hInputQueueMutex,INFINITE);
  2. ……(向msgEntityMotion中写数据)……
  3. ReleaseMutex(g_hInputQueueMutex);
复制代码

该用户从未签到

发表于 2011-9-20 10:59:21 | 显示全部楼层
很难去关注你贴上来的这么多内容,保持在渲染线程中处理三维数据避免线程冲突

该用户从未签到

发表于 2011-9-20 13:59:50 | 显示全部楼层
只要按照osg的机制处理,三维渲染方面不会冲突的~~~~~

该用户从未签到

 楼主| 发表于 2011-9-20 16:47:38 | 显示全部楼层
大部分范例程序都是在回调中直接修改节点的位置或姿态参数,或者说节点的的位置或姿态参数是在回调中生成或直接控制的,这样当然不会产生冲突。可我现在的节点参数是由网络接口获取后保存到msgEntityMotion这个结构体类型的全局变量中,再由OSG在回调时去读取msgEntityMotion中的数据,并根据数据控制节点的位置或姿态。由于网络接口是通过定时器来控制定时获取网络数据,与OSG的渲染是两个线程,并且网络线程要向msgEntityMotion中写入获取到的数据,OSG要从msgEntityMotion中读取数据用于节点更新。这就存在线程同步的问题,需要避免读写冲突啊!
我好像已经找到线程锁不起作用的原因了,就是我把g_hInputQueueMutex定义为g_pSocketManager的局部变量了,试着将g_hInputQueueMutex也改成一个全局变量,好像线程锁就起作用了,抽时间让程序多跑一段时间,看看是不是这个问题。

另外,看了SVN的好像把OSG_MFC的例子更新了,不再是用OpenThreads来管理渲染线程了。

  1. class cOSG
  2. {
  3. public:
  4.     cOSG(HWND hWnd);
  5.     ~cOSG();
  6.     void InitOSG(std::string filename);
  7.     void InitManipulators(void);
  8.     void InitSceneGraph(void);
  9.     void InitCameraConfig(void);
  10.     void SetupWindow(void);
  11.     void SetupCamera(void);
  12.     void PreFrameUpdate(void);
  13.     void PostFrameUpdate(void);
  14.     void Done(bool value) { mDone = value; }
  15.     bool Done(void) { return mDone; }
  16.     //static void Render(void* ptr);
  17.     osgViewer::Viewer* getViewer() { return mViewer; }
  18. private:
  19.     bool mDone;
  20.     std::string m_ModelName;
  21.     HWND m_hWnd;
  22.     osgViewer::Viewer* mViewer;
  23.     osg::ref_ptr<osg::Group> mRoot;
  24.     osg::ref_ptr<osg::Node> mModel;
  25.     osg::ref_ptr<osgGA::TrackballManipulator> trackball;
  26.     osg::ref_ptr<osgGA::KeySwitchMatrixManipulator> keyswitchManipulator;
  27. };
  28. class CRenderingThread : public OpenThreads::Thread
  29. {
  30. public:
  31.     CRenderingThread( cOSG* ptr );
  32.     virtual ~CRenderingThread();
  33.     virtual void run();
  34. protected:
  35.     cOSG* _ptr;
  36.     bool _done;
  37. };
复制代码


这样做和原来的方式比起来有什么优势呢?

该用户从未签到

 楼主| 发表于 2011-9-20 17:09:53 | 显示全部楼层
我现的在设计是,每个节点的位置和姿态数据更新在节点回调中处理;msgEntityMotion是一个全局动态数组,在PreFrameUpdate()中对msgEntityMotion进行分析,根据分析结果对场景的节点进行动态添加或删除;在PostFrameUpdate()中对视点运动进行处理,如改变视点的位置、方向、让视点跟踪某个节点或取消跟踪等。
这样做有什么问题吗?

该用户从未签到

发表于 2011-9-20 17:52:41 | 显示全部楼层
PreFrameUpdate(),PostFrameUpdate()这两个函数是陈旧的,观念非常错误的东东!需完全抛弃!
所有的三维视景的处理和物体的驱动请按照OSG的机制处理,与MFC没有任何关系!

该用户从未签到

 楼主| 发表于 2011-9-20 19:39:21 | 显示全部楼层
本帖最后由 x_wp 于 2011-9-20 20:13 编辑

回复 7# tianxiao888

我没说和MFC有什么关系呀,现在虽然使用osg和MFC相结合,可是在编程时我是尽量在避免OSG与MFC过多的交连,一起开发项目的别人都用MFC里的容器,在OSG中我一直使用的是STL容器,就是不想在OSG代码中包含MFC的东西。其实我是不想用MFC的,界面库我是很看好Qt等GUI库的,可我身边的人没有几个人知道Qt是什么,更别说什么WxWidgets了。大家所有的工作基本上都是在MFC中完成的,没谁愿意把在MFC中多年积累的成果转化到Qt当中,所以我要和他们合作就得和MFC打交道,这是无可奈何的事。

我们现在参与的基本上都是分布式交互实时仿真,数据是由网络中其它计算机实时进行计算的,到视景仿真这一块是不产生数据的,而只是通过网络获取数据然后用这些数据实时驱动OSG场景中节点的运动、姿态变换、添加删除、显示隐藏等等,那么就必然会出现数据读写保护的问题,就算不用MFC这个问题仍然存在。看来是我的帖子标题的问题,不应该把这个问题限定在MFC中。

另外请教一下,您说的OSG的机制具体到我现在用的这一方面是不是指的回调机制?对于节点的数据操作可以用节点回调,那么如果我要实现场景节点的动态添加、删除、显示、隐藏,怎样设计比较好呢?谢谢!
记得Array提到过GUI与OSG交互最好是用命令行缓存机制,可是我的编程水平比较低,只是能理解他说的这种方法,自己实现不了啊!

该用户从未签到

发表于 2011-9-21 09:07:05 | 显示全部楼层
简单来说就是在回调,GUIHandler中完成您对场景的操作,这样可以完全确保线程的安全性

该用户从未签到

 楼主| 发表于 2011-9-23 07:58:44 | 显示全部楼层
感谢大家的关注!通过大家的回复,我知道了在改变场景数据时应该按照osg机制,通过回调或事件来处理就可以保证线程安全。但我还是认为这只能保证osg内部线程安全,无法保证osg以外线程的安全。
还是分布交互式仿真的问题,比如网络中有一台计算机根据空气动力学专门用于计算飞机的位置和姿态,并定时向指定端口实时发送,接收的计算机需要专门开启一个与osg无关的线程来实时接收这些数据,同时将数据保存到一个变量中。然后需要在osg中从这个变量中读取飞机的位置和姿态,进而更新场景体现出飞机的运动。其实这里的线程问题是在同一个变量中多个线程同时读写数据的保护问题,而不是osg内部线程的问题。
不知我理解的对不对,求教,谢谢!

该用户从未签到

发表于 2011-9-26 08:27:04 | 显示全部楼层
多线程开发本身就是一门学问,不要总是强调osg以内或者以外,因为osg并不是多线程开发的什么引领者或者主导者

该用户从未签到

发表于 2011-9-26 11:33:42 | 显示全部楼层
看了SVN的好像把OSG_MFC的例子更新了

是锐哥贡献的吧,呵呵

该用户从未签到

发表于 2013-4-23 02:00:10 | 显示全部楼层
这个答案不错,简单来说就是在回调,GUIHandler中完成您对场景的操作,这样可以完全确保线程的安全性,能具体说说吗

该用户从未签到

发表于 2013-4-23 08:00:46 | 显示全部楼层
jacky_yu1982 发表于 2013-4-23 02:00
这个答案不错,简单来说就是在回调,GUIHandler中完成您对场景的操作,这样可以完全确保线程的安全性,能具 ...

已经说得很明确了吧,继承NodeCallback 或者 GUIEventHandler 所有的操作 放到这里面
您需要登录后才可以回帖 登录 | 注册

本版积分规则

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

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

联系我们

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