Multithread problem

Here’s some simple code I’m trying:

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define MULTITHREADED

#include <windows.h>
#include <gl/gl.h>

#include <stdio.h>

#ifdef MULTITHREADED
#include <process.h>
#endif

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define SCREEN_WIDTH  640
#define SCREEN_HEIGHT 480

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
typedef void (APIENTRY *PFNWGLEXTSWAPCONTROLPROC)(int);
static PFNWGLEXTSWAPCONTROLPROC wglSwapIntervalEXT = NULL;

static HWND gameWindow;
static HGLRC gameRC;
static int quit;

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
static int ogl_init(void)
{
	PIXELFORMATDESCRIPTOR pixeldesc;
	int pixelformat;
	HDC hDC;

	hDC = GetDC(gameWindow);

	memset(&pixeldesc, 0, sizeof pixeldesc);
	pixeldesc.nSize = sizeof(PIXELFORMATDESCRIPTOR);
	pixeldesc.nVersion = 1;

	pixeldesc.dwFlags = PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
	pixeldesc.iPixelType = PFD_TYPE_RGBA;
	pixeldesc.cColorBits = 32;

	pixeldesc.cRedBits = 0;
	pixeldesc.cGreenBits = 0;
	pixeldesc.cBlueBits = 0;
	pixeldesc.cAlphaBits = pixeldesc.cAlphaShift = 0;
	pixeldesc.cAccumBits = 32;
	pixeldesc.cAccumRedBits =
	pixeldesc.cAccumGreenBits = pixeldesc.cAccumBlueBits = 0;
	pixeldesc.cAccumAlphaBits = 0;

	pixeldesc.cDepthBits = 32;

	pixeldesc.cStencilBits = 0;
	pixeldesc.cAuxBuffers = 0;

	pixeldesc.bReserved = 0;
	pixeldesc.dwLayerMask = 0;
	pixeldesc.dwVisibleMask = 0;
	pixeldesc.dwDamageMask = 0;

	if ((pixelformat = ChoosePixelFormat(hDC, &pixeldesc)) == 0)
		return 0;

	if (pixeldesc.dwFlags & PFD_NEED_PALETTE)
		return 0;

	if (SetPixelFormat(hDC, pixelformat, &pixeldesc) == FALSE)
		return 0;

	DescribePixelFormat(hDC, pixelformat, sizeof pixeldesc, &pixeldesc);

    gameRC = wglCreateContext(hDC);
    wglMakeCurrent(hDC, gameRC);

	ReleaseDC(gameWindow, hDC);

	if (strstr((const char *)glGetString(GL_EXTENSIONS), "WGL_EXT_swap_control"))
	{
		wglSwapIntervalEXT = (PFNWGLEXTSWAPCONTROLPROC)wglGetProcAddress("wglSwapIntervalEXT");
		if (wglSwapIntervalEXT)
			wglSwapIntervalEXT(1);
	}

	return 1;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
static void ogl_shutdown(void)
{
	wglMakeCurrent(NULL, NULL);

	if (gameRC)
	{
		wglDeleteContext(gameRC);
		gameRC = 0;
	}
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
void ogl_flip(void)
{
	HDC dc;
	GLenum err;
	
	err = glGetError();
	if (err != GL_NO_ERROR)
	{
		char tmp[256];
		sprintf(tmp, "GLERROR %08X %d
", err, err);
		OutputDebugString(tmp);
	}

	dc = GetDC(gameWindow);
	SwapBuffers(dc);
	ReleaseDC(gameWindow, dc);
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#define BAR_HEIGHT 80

void ogl_draw(void)
{
	static int ry,gy,by;
	static int ri=1, gi=2, bi=3;

	glDepthRange(0.0, 1.0);
	glShadeModel(GL_SMOOTH);
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
	glPixelZoom(1.0, -1.0);

	glDisable(GL_LIGHTING);
	glDisable(GL_TEXTURE_2D);
	glDisable(GL_DEPTH_TEST);
	glDisable(GL_CULL_FACE);

	glClearDepth(1.0);
	glClearColor(0,0,0,1.0);
	glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);

	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();

	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();

	glOrtho(0.0, (GLdouble)SCREEN_WIDTH, (GLdouble)SCREEN_HEIGHT, 0.0, 0.0, 1.0);
	glViewport(0,0,SCREEN_WIDTH,SCREEN_HEIGHT);

	glEnable(GL_BLEND);
	glBlendFunc(GL_ONE, GL_ONE);

	glColor3ub(0,0,0);
	glBegin(GL_QUAD_STRIP);
		glVertex2i(0,ry);
		glVertex2i(SCREEN_WIDTH,ry);
		glColor3ub(0xff,0,0);
		glVertex2i(0,ry+BAR_HEIGHT/2);
		glVertex2i(SCREEN_WIDTH,ry+BAR_HEIGHT/2);
		glColor3ub(0,0,0);
		glVertex2i(0,ry+BAR_HEIGHT);
		glVertex2i(SCREEN_WIDTH,ry+BAR_HEIGHT);
	glEnd();

	glColor3ub(0,0,0);
	glBegin(GL_QUAD_STRIP);
		glVertex2i(0,gy);
		glVertex2i(SCREEN_WIDTH,gy);
		glColor3ub(0,0xff,0);
		glVertex2i(0,gy+BAR_HEIGHT/2);
		glVertex2i(SCREEN_WIDTH,gy+BAR_HEIGHT/2);
		glColor3ub(0,0,0);
		glVertex2i(0,gy+BAR_HEIGHT);
		glVertex2i(SCREEN_WIDTH,gy+BAR_HEIGHT);
	glEnd();
	
	glColor3ub(0,0,0);
	glBegin(GL_QUAD_STRIP);
		glVertex2i(0,by);
		glVertex2i(SCREEN_WIDTH,by);
		glColor3ub(0,0,0xff);
		glVertex2i(0,by+BAR_HEIGHT/2);
		glVertex2i(SCREEN_WIDTH,by+BAR_HEIGHT/2);
		glColor3ub(0,0,0);
		glVertex2i(0,by+BAR_HEIGHT);
		glVertex2i(SCREEN_WIDTH,by+BAR_HEIGHT);
	glEnd();

	ry += ri;
	gy += gi;
	by += bi;
	if (ry < 0) ry = 0, ri=-ri;
	else if (ry >= SCREEN_HEIGHT-BAR_HEIGHT) ry = SCREEN_HEIGHT-BAR_HEIGHT-1, ri=-ri;
	if (gy < 0) gy = 0, gi=-gi;
	else if (gy >= SCREEN_HEIGHT-BAR_HEIGHT) gy = SCREEN_HEIGHT-BAR_HEIGHT-1, gi=-gi;
	if (by < 0) by = 0, bi=-bi;
	else if (by >= SCREEN_HEIGHT-BAR_HEIGHT) by = SCREEN_HEIGHT-BAR_HEIGHT-1, bi=-bi;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
#ifdef MULTITHREADED
static unsigned int __stdcall runasthread(void *args)
{
	HDC dc;

	args;

	dc = GetDC(gameWindow);
	wglMakeCurrent(dc, gameRC);
	ReleaseDC(gameWindow, dc);

	while (!quit)
	{
		ogl_draw();
		ogl_flip();
	}

	_endthreadex(0);
	return 0;
}
#endif

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
LRESULT CALLBACK WindowProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
	switch (msg )
	{
		case WM_KEYDOWN:
			switch (wParam)
			{
				case VK_ESCAPE:
					PostQuitMessage(0);
					break;
			}
			break;

		case WM_ERASEBKGND:
			return 1;

		case WM_CLOSE:
		case WM_DESTROY:
			PostQuitMessage(0);
			break;

		default:
			return DefWindowProc(hwnd, msg, wParam, lParam);
			break;
	}

	return 0;
}

//-----------------------------------------------------------------------------------------------------------------
//
//-----------------------------------------------------------------------------------------------------------------
//
//
//
//-----------------------------------------------------------------------------------------------------------------
static char GLSampleClass[32] = "GLSampleClass";

int WINAPI WinMain(HINSTANCE this_inst, HINSTANCE prev_inst, LPSTR cmdline, int cmdshow)
{
	WNDCLASS	wc;
	int style, exstyle;
	RECT rect;

	wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
	wc.lpfnWndProc = (WNDPROC) WindowProc;
	wc.cbClsExtra = 0;
	wc.cbWndExtra = 0;
	wc.hInstance = this_inst;
	wc.hIcon = LoadIcon(NULL, (LPCSTR)IDI_WINLOGO);
	wc.hCursor = LoadCursor(NULL, IDC_ARROW);
	wc.hbrBackground = 0;
	wc.lpszMenuName = NULL;
	wc.lpszClassName = GLSampleClass;
	RegisterClass(&wc);

	style = WS_OVERLAPPED|WS_SYSMENU|WS_CAPTION;
	exstyle = WS_EX_APPWINDOW;
	gameWindow = CreateWindowEx(
		0,
		GLSampleClass,			// class 
		"OpenGL Sample",
		style,
		CW_USEDEFAULT,CW_USEDEFAULT,	// init. x,y pos 
		SCREEN_WIDTH,SCREEN_HEIGHT,
		NULL,				// parent window 
		NULL,				// menu handle 
		this_inst,			// program handle 
		NULL				// create parms 
		);

	GetWindowRect(gameWindow, &rect);
	AdjustWindowRectEx(&rect, style, FALSE, exstyle);
	SetWindowPos(gameWindow, NULL, 0,0, rect.right-rect.left, rect.bottom-rect.top, SWP_NOMOVE);

	ShowWindow(gameWindow, cmdshow);
	UpdateWindow(gameWindow);

	if (ogl_init() == 0)
	{
		MessageBox(gameWindow, "Failed Initialising OpenGL", "Failed", MB_OK);
		return 0;
	}
	
#ifdef MULTITHREADED
	wglMakeCurrent(NULL, NULL);
	_beginthreadex(NULL, 0, runasthread, NULL, 0, NULL);
#endif

	quit = 0;
	do
	{
		MSG msg;
		while (PeekMessage(&msg,NULL,0,0, PM_NOREMOVE))
		{
			if (GetMessage(&msg,NULL,0,0)>0)
			{
				TranslateMessage(&msg);
				DispatchMessage(&msg);
			}
			else
			{
				quit = 1;
				break;
			}
		}
#ifndef MULTITHREADED
		ogl_draw();
		ogl_flip();
#else
		Sleep(50);
#endif

	} while (!quit);

	ogl_shutdown();
	
	return 0;
}

It should work with or without MULTITHREADED defined.

Symptoms are:
MULTITHREADED NOT defined.
All OK

MULTITHREADED defined.
sometimes the display runs correctly.
sometimes the display is not updated.
sometimes the display is not updated but dragging the window round forces an update.
sometimes there is a delay before anything is displayed.

The problem seems only to exist on Windows Vista 32bit. Windows XP SP2 works fine.

This is on an nVidia 8600GT, latest drivers, Core2 Duo.

Has anyone got any ideas?

Jim

Can anyone confirm that they get the same problems?

I’ve found a post here that suggests adding

SetProcessAffinityMask(GetCurrentProcess(), 0x1);

at the very start of the program might fix multithread problems.

That does indeed fix the problem, but it’s obvious the race condition is not in my sample.

Jim