您的位置:首页 > 其它

【转】SiftGPU不自动释放GL context的bug及其修正方法

2013-03-12 16:28 417 查看
转自:http://blog.sina.com.cn/s/blog_4298002e01019gle.html

很早以前就在使用wuchangchang开发的SiftGPU库,以前就经常出现运行完Sift后程序崩溃的问题,但是一直没有空闲去跟踪这个问题的所在。直到昨天才修正了这个bug。

仔细阅读SiftGPU的代码可以发现,SiftGPU的CreateContextGL()函数调用GlobalUtil类的静态方法GlobalUtil::CreateWindowEZ()创建了一个静态的LiteWindow对象实例,供GLSL程序使用。代码在GlobalUtil.cpp内,如下:

int GlobalUtil::CreateWindowEZ()

{

static LiteWindow window;

return CreateWindowEZ(&window);

}

注意,这个LiteWindow对象不是以指针形式声明的,而且整个程序再没有销毁过该LiteWindow对象,即便SiftGPU被销毁之后,这个对象仍然存在,直到包含SiftGPU的对象被析构或者包含SiftGPU的函数退出——此时LiteWindow对象依然存在,但是其GL上下文已经丢失,相关指针变为野指针。

这种机制为后面的程序带来了隐藏的bug:如果我们在主程序结束前都不析构包含SiftGPU的对象,等到主程序结束时再由系统自动销毁,则程序不会出现任何问题。但是如果我们一运行完SiftGPU的功能就把包含SiftGPU的对象析构了,然后再等主程序结束,就会出现LiteWindow对象无法被析构的错误——因为该对象已经在析构包含SiftGPU的对象时产生了野指针,系统再对其回收就会出现问题。

其实wuchangchang的这个代码本意是把GlobalUtil类设计成一个单体(singleton),只创建一个LiteWindow实例。然而由于该对象不是以指针形式声明的,所以导致无法主动销毁。为了修正这个bug,我们需要对GlobalUtil的代码进行一些修改,将其变成一个完全的单体模式。修改方法如下:

1)打开GlobalUtil.h,删除static int CreateWindowEZ(LiteWindow* window)方法,并把static int CreateWindowEZ()方法改为:

static LiteWindow* CreateWindowEZ();

添加一个销毁实例的方法:

static void DestroyWindowEZ();

添加一个保护的静态成员变量:

protected:

static LiteWindow *m_pWindow;

2)打开GlobalUtil.cpp,删除int GlobalUtil::CreateWindowEZ(LiteWindow* window)和int GlobalUtil::CreateWindowEZ()的代码,添加如下代码:

LiteWindow *GlobalUtil::m_pWindow = NULL;



LiteWindow* GlobalUtil::CreateWindowEZ()

{

if (m_pWindow == NULL)

{

m_pWindow = new LiteWindow;

}



if (!m_pWindow->IsValid())

{

m_pWindow->Create(_WindowInitX, _WindowInitY, _WindowDisplay);

}



if(m_pWindow->IsValid())

{

m_pWindow->MakeCurrent();

}

else

{

std::cerr << "Unable to create OpenGL Context!\n";

std::cerr << "For nVidia cards, you can try change to CUDA mode in this case\n";

}

return m_pWindow;

}



void GlobalUtil::DestroyWindowEZ()

{

if (m_pWindow != NULL)

{

delete m_pWindow;

m_pWindow = NULL;

}

}

3)在SiftGPU.h中的SiftGPU类和SiftMatchGPU类分别添加:

SIFTGPU_EXPORT virtual void DestroyContextGL();

4)在SiftGPU.cpp中添加:

void SiftGPU::DestroyContextGL()

{

return GlobalUtil::DestroyWindowEZ();

}

在SiftMatchGPU.cpp中添加:

void SiftMatchGPU::DestroyContextGL()

{

GlobalUtil::DestroyWindowEZ();

}

5)修改SiftGPU.h中的SIFTGPU_EXPORT int CreateLiteWindow(LiteWindow* window)为:

SIFTGPU_EXPORT LiteWindow* CreateLiteWindow();

6)修改GlobalUtil.cpp中的int CreateLiteWindow(LiteWindow* window)为:

LiteWindow* CreateLiteWindow()

{

return GlobalUtil::CreateWindowEZ();

}

7)在自己的代码中使用完Sift的地方,手动调用析构GL context的函数,如下:

假设变量:SiftGPU *pSift;

pSift->DestroyContextGL();

或者:SiftMatchGPU *pSiftMatch;

pSiftMatch->DestroyContextGL();

具体调用哪句,视最后使用哪个对象而定。



自此,我们的程序就不会出现重复释放LietWindow的错误了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: