PDA

View Full Version : Multithreaded OpenGL and wglMakeCurrent() crash



Bekos
02-18-2012, 10:17 AM
Hello everybody!

I have a strange problem regarding multi-threading and multiple OpenGL contexts.
In my application I have my main thread, which is also the rendering thread, and I have a worker thread which acts as a resource loader (loading data from disk and creating VBOs).
During my application initialization I create both contexts in the main thread, and I just pass one context to the worker thread like this:
(I have included some pseudocode in order to explain my problem easier)

MAIN Thread:


void init()
{
contextMain = createContext();
contextWorker = createContext();
wglMakeCurrent(contextMain);
wglShareLists(contextMain,contextWorker); // If I remove this line nothing changes, the problem persists.
loader = createLoader(contextWorker);
loader->startThread();
}

Then, inside my worker thread, I make the supplied context current and I enter the thread loop.

WORKER Thread:


void ThreadedLoader::threadMain()
{
wglMakeCurrent(contextWorker);
while(!shutdownRequested)
{
// empty code block for now
}
}

So far so good. The problem arises when I try to shut down the application. First I terminate the worker thread and then I try to make the worker context current in the main thread like this:

MAIN Thread:


void shutdown()
{
loader->requestShutdownAndWaitUntilThreadIsDead();
wglMakeCurrent(contextWorker); // <--------------- It crashes here
wglMakeCurrent(NULL,NULL);
wglDeleteContext(contextWorker);
releaseDC(contextWorker);
wglMakeCurrent(contextMain);
wglMakeCurrent(NULL,NULL);
wglDeleteContext(contextMain);
releaseDC(contextMain);
}

When I try to make the worker context current in the main thread using wglMakeCurrent, I get an access violation exception inside nvoglv32.dll. Isn't the above the right way to release the worker context?
I have to mention that I do not get the crash every time I run the application, but usually once every 3 times.

System: Win7x64, nVidia9600MGT driver: 285.62

Thanks a lot for your time guys and sorry for the very long post.

Cheers,
Bekos

carsten neumann
02-18-2012, 02:02 PM
Your thread function should end with wglMakeCurrent(NULL, NULL), otherwise you are attempting to make contextWorker current in two threads (namely the worker thread and the main thread) at the point where you are seeing the crash.

Aleksandar
02-18-2012, 02:04 PM
First of all, are you using GL3+ contexts or 2.1? If it those are GL3+ contexts wglShareLists really does nothing, since sharing is defined in the context creation time.

Second, wglmakeCurrent requires two parameters. In your "pseudo-code" HDC parameter is ignored. Let's assume you are passing valid HDC.





void shutdown()
{
loader->requestShutdownAndWaitUntilThreadIsDead();
wglMakeCurrent(contextWorker); // <--------------- It crashes here
wglMakeCurrent(NULL,NULL);
wglDeleteContext(contextWorker);
releaseDC(contextWorker);
wglMakeCurrent(contextMain);
wglMakeCurrent(NULL,NULL);
wglDeleteContext(contextMain);
releaseDC(contextMain);
}



You should call wglMakeCurrent(NULL,NULL) on exiting worker thread.
Also, I don't understand why are you calling wglMakeCurrent just to call again with NULL parameter.

Releasing rendering context is quite simple:


wglMakeCurrent(NULL,NULL);
wglDeleteContext(hRC);
// optionally
ReleaseDC(pDC);


Just be sure that you have exited worker thread in the moment of the context release. You need a synchronization. That's why it crashes from time to time.

Bekos
02-18-2012, 02:17 PM
Hello again!

You are both right! I am missing the wglMakeCurrent(NULL,NULL) at the end of the worker thread.

@Aleksandar: Looks like I did misunderstood what wglMakeCurrent(NULL,NULL) does. This is why I have this redundant code there.

Thank you both guys! Now the application runs and shuts down with no crashes!

Cheers,
Bekos