Part of the Khronos Group
OpenGL.org

The Industry's Foundation for High Performance Graphics

from games to virtual reality, mobile phones to supercomputers

Results 1 to 3 of 3

Thread: integrating threads with OpenGL

Hybrid View

  1. #1
    Junior Member Newbie
    Join Date
    Mar 2012
    Location
    Angus
    Posts
    5

    integrating threads with OpenGL

    I'm trying to make a very simple openGL animation of the classic dining philosophers problem. (http://en.wikipedia.org/wiki/Dining_...ophers_problem)

    I have the basic program working with just C++ and cout's etc. but when I try and represent this using simple primitives things go wrong. As you can see when you run it, 3 (sometimes 4) of the philosophers eat at the same time which is impossible and sometimes one or more doesn't finish at all. Red means thinking, blue means eating and green means finished eating. here is my code:

    main:

    Code :
    #include <windows.h>
    #include <stdio.h>
    #include <mmsystem.h>
    #include <math.h>
    #include "philosopher.h"
    #include <gl/gl.h>
    #include <gl/glu.h>
     
     
    #define COLOUR_DEPTH 16	//Colour depth
    #define AMOUNT 5
     
    typedef struct Mouse
    {
    	int x,y;
    }Mouse;
     
     
     
     
    HWND        ghwnd;
    HDC			ghdc;
    HGLRC		ghrc;			//hardware RENDERING CONTEXT
    HINSTANCE	ghInstance;
    RECT		gRect;
    RECT		screenRect;
     
     
    int S_WIDTH	 =	800;		//client area resolution
    int S_HEIGHT =	600;
     
    HANDLE * chops = new HANDLE[AMOUNT];
    HANDLE * philo_guys = new HANDLE[AMOUNT];
    //chops 
     
    Philosopher one("1", &amp;chops[0], &amp;chops[1]); 
    Philosopher two("2", &amp;chops[1], &amp;chops[2]); 
    Philosopher three("3", &amp;chops[2], &amp;chops[3]);
    Philosopher four("4", &amp;chops[3], &amp;chops[4]);
     Philosopher five("5", &amp;chops[4], &amp;chops[0]);
     
    bool		keys[256];
     
     
    Mouse MousePos;
     
     
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);
    void DrawScene();
    void DrawTable();
     
     
     
    HWND CreateOurWindow(LPSTR strWindowName, int width, int height, DWORD dwStyle, bool bFullScreen, HINSTANCE hInstance)
    {
    	HWND hwnd;
     
    	WNDCLASS wcex;
     
    	memset(&amp;wcex, 0, sizeof(WNDCLASS));
    	wcex.style			= CS_HREDRAW | CS_VREDRAW;		
    	wcex.lpfnWndProc	= WndProc;		
    	wcex.hInstance		= hInstance;						
    	wcex.hIcon			= LoadIcon(NULL, IDI_APPLICATION);; 
    	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);		
    	wcex.hbrBackground	= (HBRUSH) (COLOR_WINDOW+1);
    	wcex.lpszMenuName	= NULL;	
    	wcex.lpszClassName	= "FirstWindowClass";	
     
     
    	RegisterClass(&amp;wcex);// Register the class
     
    	dwStyle = WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
     
    	ghInstance	= hInstance;// Assign our global hInstance to the window's hInstance
     
    	//Set the Client area of the window to be our resolution.
    	RECT glwindow;
    	glwindow.left		= 0;		
    	glwindow.right		= width;	
    	glwindow.top		= 0;		
    	glwindow.bottom		= height;	
     
    	AdjustWindowRect( &amp;glwindow, dwStyle, false);
     
    	//Create the window
    	hwnd = CreateWindow(	"FirstWindowClass", 
    							strWindowName, 
    							dwStyle, 
    							0, 
    							0,
    							glwindow.right  - glwindow.left,
    							glwindow.bottom - glwindow.top, 
    							NULL,
    							NULL,
    							hInstance,
    							NULL
    							);
     
    	if(!hwnd) return NULL;// If we could get a handle, return NULL
     
    	ShowWindow(hwnd, SW_SHOWNORMAL);	
    	UpdateWindow(hwnd);					
    	SetFocus(hwnd);						
     
    	return hwnd;
    }
     
    bool SetPixelFormat(HDC hdc) 
    { 
        PIXELFORMATDESCRIPTOR pfd = {0}; 
        int pixelformat; 
     
        pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);	// Set the size of the structure
        pfd.nVersion = 1;							// Always set this to 1
    	// Pass in the appropriate OpenGL flags
        pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER; 
        pfd.dwLayerMask = PFD_MAIN_PLANE;			// standard mask (this is ignored anyway)
        pfd.iPixelType = PFD_TYPE_RGBA;				// RGB and Alpha pixel type
        pfd.cColorBits = COLOUR_DEPTH;				// Here we use our #define for the color bits
        pfd.cDepthBits = COLOUR_DEPTH;				// Ignored for RBA
        pfd.cAccumBits = 0;							// nothing for accumulation
        pfd.cStencilBits = 0;						// nothing for stencil
     
    	//Gets a best match on the pixel format as passed in from device
        if ( (pixelformat = ChoosePixelFormat(hdc, &amp;pfd)) == false ) 
        { 
            MessageBox(NULL, "ChoosePixelFormat failed", "Error", MB_OK); 
            return false; 
        } 
     
    	//sets the pixel format if its ok. 
        if (SetPixelFormat(hdc, pixelformat, &amp;pfd) == false) 
        { 
            MessageBox(NULL, "SetPixelFormat failed", "Error", MB_OK); 
            return false; 
        } 
     
        return true;
    }
     
    void ResizeGLWindow(int width, int height)// Initialize The GL Window
    {
    	if (height==0)// Prevent A Divide By Zero error
    	{
    		height=1;// Make the Height Equal One
    	}
     
    	glViewport(0,0,width,height);
     
    	glMatrixMode(GL_PROJECTION);
    	glLoadIdentity();
     
    	//calculate aspect ratio
    	gluPerspective(45.0f,(GLfloat)width/(GLfloat)height, 1 ,150.0f);
     
    	glMatrixMode(GL_MODELVIEW);// Select The Modelview Matrix
    	glLoadIdentity();// Reset The Modelview Matrix
    }
     
    void InitializeOpenGL(int width, int height) 
    {  
        ghdc = GetDC(ghwnd);//  sets  global HDC
     
        if (!SetPixelFormat(ghdc))//  sets  pixel format
            PostQuitMessage (0);
     
     
        ghrc = wglCreateContext(ghdc);	//  creates  rendering context from  hdc
        wglMakeCurrent(ghdc, ghrc);		//	Use this HRC.
     
    	ResizeGLWindow(width, height);	// Setup the Screen
    }
     
     
     
    void Init(HWND hwnd)
    {
    	ghwnd = hwnd;
    	GetClientRect(ghwnd, &amp;gRect);	//get rect into our handy global rect
    	InitializeOpenGL(gRect.right, gRect.bottom);// initialise openGL
     
    	//OpenGL settings
    	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
    	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
    	glClearDepth(1.0f);									// Depth Buffer Setup
    	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
    	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
    	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
     
    	//Also, do any other setting ov variables here for your app if you wish. 
    }
     
    void DrawScene() 
    {
    	int i=0;
     
    	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);// Clear The Screen And The Depth Buffer
    	glLoadIdentity();// load Identity Matrix
     
    	//set camera looking down the -z axis,  6 units away from the center
    	gluLookAt(0, 0, 6,     0, 0, 0,     0, 1, 0); //Where we are, What we look at, and which way is up
     
     
    	glColor3f(1.0,1.0,1.0);
    	DrawTable();
    	glClearColor(0,0,0,0);
    	glPushMatrix();
    	one.Draw(-2,-2,0,45,0,0,-1);
    	glPopMatrix();
     
    	glPushMatrix();
    	two.Draw(2,-2,0,45,0,0,1);
    	glPopMatrix();
     
    	glPushMatrix();
    	three.Draw(2,2,0,135,0,0,1);
    	glPopMatrix();
     
    	glPushMatrix();
    	four.Draw(-2,2,0,135,0,0,-1);
    	glPopMatrix();
     
    	glPushMatrix();
    	five.Draw(-2,0,0,90,0,0,-1);
    	glPopMatrix();
     
     
     
    	SwapBuffers(ghdc);// Swap the frame buffers.
     
    }		
     
    void DrawTable()
    {
    	glScalef(0.5,0.5,0.5);
    	glBegin (GL_QUADS);//Begin drawing state
    		glVertex3f(-1.0f, -1.0f, 0.0f); // The bottom left corner  
    		glVertex3f(-1.0f, 1.0f, 0.0f); // The top left corner  
    		glVertex3f(1.0f, 1.0f, 0.0f); // The top right corner  
    		glVertex3f(1.0f, -1.0f, 0.0f); // The bottom right corner
    	glEnd();//end drawing
    }
     
     
    void Cleanup()
    {
    	if (ghrc)
    	{
    		wglMakeCurrent(NULL, NULL);	// free rendering memory
    		wglDeleteContext(ghrc);		// Delete our OpenGL Rendering Context
    	}
     
    	if (ghdc) 
    	ReleaseDC(ghwnd, ghdc);			// Release our HDC from memory
     
    	UnregisterClass("FirstWindowClass", ghInstance);// Free the window class
     
    	PostQuitMessage (0);		// Post a QUIT message to the window
    }
     
     
     
    LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
     
     
        switch (message)											
        {														
    		case WM_CREATE:	
    			break;
     
    		case WM_SIZE:
    			//resize the open gl window when the window is resized
    			ResizeGLWindow(LOWORD(lParam),HIWORD(lParam));
    			GetClientRect(hwnd, &amp;gRect);
    			break;	
     
    		case WM_KEYDOWN:
    			keys[wParam]=true;
    			break;
     
    		case WM_KEYUP:
    			keys[wParam]=false;
    			break;
     
    		case WM_MOUSEMOVE:
    			MousePos.x = LOWORD (lParam);
    			MousePos.y = HIWORD (lParam);
    			break;
     
    		case WM_PAINT:
     
     
    		    break;		
     
    		case WM_DESTROY:	
     
    			PostQuitMessage(0);	
     
    			break;				
    	}													
     
    	return DefWindowProc (hwnd, message, wParam, lParam);		
     
    }
     
    unsigned int __stdcall PhiloInit(void * phil) //initiliaze eating
    {
     
        Philosopher * whichever = static_cast<Philosopher *>(phil);
        whichever->Eat(); //eat 
    	return NULL;
    }
     
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int nCmdShow)			
    {	
    	HWND		hwnd;
        MSG         msg;	
     
     
     
    	//initialise and create window
    	hwnd = CreateOurWindow("Dining Philosophers", S_WIDTH, S_HEIGHT, 0, false, hInstance);	
    	if(hwnd == NULL) return true;
     
    	//initialise opengl and other settings
    	Init(hwnd);
     
    	 for (int i = 0; i < AMOUNT; i++)
        {
            chops[i] = CreateMutex(0, 0, 0);
        }
     
     
     
        philo_guys[0] = (HANDLE)_beginthreadex(0, 0, &amp;PhiloInit, (void *)&amp;one, 0, 0);
        philo_guys[1] = (HANDLE)_beginthreadex(0, 0, &amp;PhiloInit, (void *)&amp;two, 0, 0);
        philo_guys[2] = (HANDLE)_beginthreadex(0, 0, &amp;PhiloInit, (void *)&amp;three, 0, 0);
        philo_guys[3] = (HANDLE)_beginthreadex(0, 0, &amp;PhiloInit, (void *)&amp;four, 0, 0);
        philo_guys[4] = (HANDLE)_beginthreadex(0, 0, &amp;PhiloInit, (void *)&amp;five, 0, 0);
     
        for (int i = 0; i < AMOUNT; i++)
        {
            CloseHandle(chops[i]);
        }
     
    	while (true)					
        {							
    		if (PeekMessage(&amp;msg,NULL,0,0,PM_REMOVE))
    		{
    		    if (msg.message==WM_QUIT)
    				break;
    			TranslateMessage (&amp;msg);							
    			DispatchMessage (&amp;msg);
    		}
     
    		else
    		{		
    			//any intensive proccessing for the app,  do it here. 
    			DrawScene();
     
     
    		}
        }
     
    	return msg.wParam ;										
    }

    philosopher.cpp:

    Code :
    #include "philosopher.h"
    #include <windows.h>
    #include <stdio.h>
    #include <mmsystem.h>
    #include <math.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
    using namespace std;
     
    Philosopher::Philosopher()
    {
     state=1;
    }
     
     
    Philosopher::~Philosopher()
    {
     
    }
     
     
    void Philosopher::Think()
    {
     
            cout << name << " is now thinking\n";
            Sleep(2000);
            Eat();
     
    }
     
    void Philosopher::Eat()
    {
     
     
            if (!has_eaten){
    			state = 1;
     
                cout << name << " is attempting to eat\n";
                if (WaitForSingleObject(*left_chop, 2000) == WAIT_TIMEOUT || WaitForSingleObject(*right_chop, 2000) == WAIT_TIMEOUT)
                {
                    cout << name << " can't eat at this point in time. " << name << " decides to think\n";
     
                    Think();
                }
                else
                {
                    cout << name << " is now eating\n";
    				state = 2;
                    Sleep(5000); //eating time 
                    ReleaseMutex(*left_chop); ReleaseMutex(*right_chop); //let go of chopstick
                    cout << name << " has finished eating <<<<<<----\n";
    				state = 3;
                    has_eaten = true;
                }
            }
            else
                cout << name << " has already eaten\n";
     
     
    		return;
     
    }
     
    void Philosopher::Draw(GLfloat x, GLfloat y, GLfloat z, GLfloat Angle, GLfloat Rx, GLfloat Ry, GLfloat Rz)
    {
     
    if (state == 1)
    glColor3f(1.0,0.0,0.0);
    if (state == 2)
    glColor3f(0.0,0.0,1.0);
    if (state == 3)
    glColor3f(0.0,1.0,0.0);
     
     
    	glTranslatef(x,y,z);
    	glRotatef(Angle,Rx,Ry,Rz);
    	glScalef(0.3f,0.7f,0.7f);
        glBegin (GL_TRIANGLES);//Begin drawing state
    		glVertex3f(	0.0, 1.0, 0.0);	
    		glVertex3f(-1.0, 0.0, 0.0);
    		glVertex3f( 1.0, 0.0, 0.0);
    	glEnd();//end drawing
     
    }

    philosopher.h

    Code :
    #ifndef __H_PHILOSOPHER__
    #define __H_PHILOSOPHER__
     
    #include <iostream>
    #include <process.h>
    #include <windows.h>
    #include <string>
    #include <time.h>
    #include <gl/gl.h>
    #include <gl/glu.h>
     
    using namespace std;
     
    class Philosopher
    {
    private:
        HANDLE * left_chop, * right_chop;
        string name;
     
     
    public:
    	 Philosopher();
    		~ Philosopher();
        Philosopher(string phil_name, HANDLE * left_chop_handle, HANDLE * right_chop_handle) :
                                    name(phil_name), left_chop(left_chop_handle), right_chop(right_chop_handle){ has_eaten = false; }
        void Eat();
         bool has_eaten;
        void Think();
        void Draw(GLfloat x, GLfloat y, GLfloat z, GLfloat Angle, GLfloat Rx, GLfloat Ry, GLfloat Rz);
    	int state;
    };
     
    #endif

    thanks for any help

  2. #2
    Member Regular Contributor
    Join Date
    Apr 2010
    Posts
    494

    Re: integrating threads with OpenGL

    The member variable Philosopher::state is modified concurrently by the threads and read by your DrawScene function, but there is no mutex or other thread synchronization to protect access to it.

    Also, have you seen http://www.opengl.org/wiki/OpenGL_and_multithreading?

    One last point: since Philosopher::Eat and Philosopher::Think call each other repeatedly there is a chance you run out of stack space (probably not in practice with only 5 philosophers and the long sleeps). You could avoid that if your thread function would use a loop that terminates once a philosopher has eaten.

  3. #3
    Junior Member Newbie
    Join Date
    Mar 2012
    Location
    Angus
    Posts
    5

    Re: integrating threads with OpenGL

    thanks for the reply, I've been trying to add a mutex to protect that member variable but I'm still getting unpredictable (and wrong) results.

    I added a private handle "State_Mutex" to the class.

    and put
    Code :
     State_Mutex = CreateMutex(NULL, false, NULL);
    in the constructor

    and put
    Code :
     WaitForSingleObject(State_Mutex, INFINITE);
    			state = state + 1;
    			ReleaseMutex(State_Mutex);
    each time the state is changed.


    I also tried using a mutex class but that didn't seem to work either...
    what am I doing wrong? Thanks for any help

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •