0

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.

teodron
  • 1,410
  • 1
  • 20
  • 41
  • Why do you want to use a *global* variable when using threads? – Bartek Banachewicz Dec 14 '12 at 16:09
  • Because of the FreeGLUT library. It needs some kind of a global variable to control and pass data to the render function. Its callbacks don't work with any arguments when it comes to rendering or idling (e.g. the display callback in this case). – teodron Dec 14 '12 at 16:12
  • So why are you using FreeGLUT library which requires a global variable from you (I bet it doesn't)? – Bartek Banachewicz Dec 14 '12 at 16:13
  • It doesn't "require" a global to get its flow control from? (I frankly haven't seen any code using GLUT without globals to date) Well, I'm using it because I don't have the time to write my own OpenGL wrapper library (but I guess we're digressing from the purpose of my question). – teodron Dec 14 '12 at 16:16
  • We're back by now. Trying to "simplify" your life by such library, when you are using more advanced things (like multithreaded rendering) can result in more headache than writing everything from scratch. Just an opinion. – Bartek Banachewicz Dec 14 '12 at 16:18
  • You haven't specified what's going on in that other thread but GLUT isn't really designed to be multithreaded, so if you are making GLUT calls on that other thread I would not be surprised if seriously broken things are happening. (It also shows its age and lack of foresight in other areas, such as not providing context pointers in the callbacks, and not supporting Unicode.) – asveikau Dec 14 '12 at 16:19
  • Besides the critique aimed at the usage of that library, I still have no idea why that destructor gets invoked twice just by setting the `atexit` callback as illustrated in my pseudocode snippet. – teodron Dec 14 '12 at 16:20

1 Answers1

1

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.

Nikos C.
  • 50,738
  • 9
  • 71
  • 96
  • Thanks, that works as expected in the sense that it returns from the main loop. The destructor still gets called twice; I'll check it again disabling multithreading and see how that works out. – teodron Dec 14 '12 at 16:26
  • Problem solved, thanks a lot - FreeGLUT is returning control to the main function and resources are now consistently cleaned. – teodron Dec 17 '12 at 10:51