Chinaunix首页 | 论坛 | 博客
  • 博客访问: 96745
  • 博文数量: 17
  • 博客积分: 366
  • 博客等级: 一等列兵
  • 技术积分: 235
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-16 16:31
文章分类

全部博文(17)

文章存档

2011年(17)

我的朋友

分类: C/C++

2011-06-22 15:47:50

最近忙着将开源的三维图形引擎OSG封装成ActiveX控件陆续遭遇了一些问题,今天将其中比较有趣的一个记录在此不光是因为问题涉及到非常经典的Meyers单件的应用局限,还有一个原因在于问题虽然得到解决,但是对于其个中因果并不了然。记录的目的也作为提醒路漫漫匹夫怎敢懈怠。

    控件封装好之后,嵌入IE没有问题,嵌入C#窗体时如果加载osgEarth数据则会在析构时出现异常,体现为访问内存冲突。加载控件源码调试之后错误定位在下面一行:

     OpenThreads::ScopedLock<OpenThreads::Mutexlock(s_engineNodeCacheMutex);

      EngineNodeCache::iterator k = getEngineNodeCache().find( uid );

      if (k != getEngineNodeCache().end())

      {

        getEngineNodeCache().erase(k);

        OE_DEBUG << LC << "Unregistered engine " << uid << std::endl;

     }

     很容易知道在这种情况下getEngineNodeCache()返回了空集合,进而产生了内存访问异常错误。但是当我简单的在find函数之前加了非空保护之后,却遇到了另外一个让我大跌眼镜的问题,程序出现了内存泄露。看来这个空集合的出现不正常的。进一步看了osgEarth的相关定义,发现存在一个Meyers单件。

static

EngineNodeCachegetEngineNodeCache()

{

     static EngineNodeCache s_cache;

     return s_cache;

}

从代码看不出问题,而且进一步的调试也证明在桌面程序和IE里该单件都能够正常析构,仅在C#窗体中会出现错误。困惑之余注意到在C#窗体应用时于加锁一步要等待一定时间,而前两者则几乎立刻执行了。难道这里存在一个线程同步或者说涉及到了Meyers模式的多线程应用了?联想到以前读过Imferfect C++中关于meyers单件线程安全的描述,似乎这里存在一个疑点。

     假设1、在C#的窗体中,出于某些原因,发生了并发的getEngineNodeCache线程,那么的确有可能出现死亡对话问题,会有多于一个静态EngineNodeCache 被创建,那么如果析构的时候访问了错误的对象,从而产生这个问题。那么是什么原因让C#窗体中产生了原本不存在的并发?

     假设2、如果没有产生并发getEngineNodeCache理论上静态对象会在main函数之后进行析构,那么mian函数结束之前EngineNod析构时,s_cache会返回空值就不好理解了。这里并没有静态成员间的依赖,析构时不应出现此类问题。是否在C#中调用COM会产生某种特别的内存管理方式,这种方式打乱了原本C++中的惯例?是否C#对于栈上存在的静态成员也进行了统一处理?遗憾的是我对C#的掌握还达不到这样的程度。无从追查下去。

     最终通过将Meyers单件模式修改成双向加锁的单件顺利的解决了这个问题,但是我仍然不能证实前面的两个疑问。

阅读(1978) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~