Search code examples
c++multithreadingfreeglut

C++ TinyThread and OpenGL with FreeGLUT


The problem I've encountered is generated by the probable misuse of threading within a simplistic FreeGLUT C++ application.

Since exiting the glutMainLoop() cannot be done elegantly, I rely on glutLeaveMainLoop() to do some of the work, but this one doesn't really give the control back to the program's main function. I have a global pointer that will be set in the main function, prior to the GL calls, to an object instance created on the heap. Without using the atexit callback, nobody will call the delete operator on this instance, although I placed such an operation after the glutMainLoop call (now commented because of its futility).

Here's a pseudocode for what I'm doing (I won't post the actual code since it's too long to filter):

CWorld* g_world;

AtExit()
{
 delete g_world;
}
void main()
{
  atexit(AtExit);
  // create an instance of an object that creates a thread in its constructor
  // via the new operator and joins this thread in its destructor
  // calling the delete operator on that pointer to the thread instance
  CWidget thisObjectCreatesATinyThread;

  g_world = new CWorld();
  ...
  glutMainLoop();
  // delete g_world;
}

Note that in the main function, I also included a widget instance that does some work via a thread created in its constructor. This thread is joined in its destructor, then the memory is deallocated via a delete.

The wrong behaviour: without setting the atexit callback, I get a resource leak, since the destructor of the CWorld object won't get called. If I set this callback, then the delete operator gets called twice for some reason, even though the AtExit function is called only once.

What is the place to look for the source of this odd behaviour?

Even if I disable the CWidget instantiation, I still get the peculiar behaviuor.


Solution

  • I assume you're not using the original GLUT library (since it's ancient) but rather FreeGLUT, which is the most wide-spread GLUT implementation. In order to have glutMainLoop() return, you would do:

    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_CONTINUE_EXECUTION);
    

    before calling glutMainLoop(). This will cause it to return if there are no more active top-level windows left when you call glutLeaveMainLoop(). If you don't care about still active windows, instead do:

    glutSetOption(GLUT_ACTION_ON_WINDOW_CLOSE, GLUT_ACTION_GLUTMAINLOOP_RETURNS);
    

    You probably have to include <GL/freeglut.h> instead of <GL/glut.h> in order to get the definitions.