Jump to content
  • Advertisement
Sign in to follow this  
giant

Mutex never locks

This topic is 3755 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi I have been looking online and on gamedev forums for this problem, but most people appear to suffer from their programs locking up. I have the opposite. I want to lock thread A at a specific point until thread B completes. I am working in VS 2005/C++ and using Mutex's. My Mutex Code is like
#include "Mutex.h"

CMutex::CMutex()
{
	m_Mutex = NULL;
}

CMutex::~CMutex()
{
	if (NULL != m_Mutex)
		Close();
}

void CMutex::Create()
{
	m_Mutex = CreateMutex(NULL, FALSE, NULL);
}

void CMutex::Close()
{
	if (NULL != m_Mutex)
	{
		CloseHandle(m_Mutex);
		m_Mutex = NULL;
	}
}

BOOL CMutex::Lock(int p_iTimeout)
{
	switch(WaitForSingleObject(m_Mutex, p_iTimeout))
	{
		case WAIT_OBJECT_0:
			return TRUE;

		case WAIT_ABANDONED:
		case WAIT_TIMEOUT:
		case WAIT_FAILED:
			return FALSE;
	}

	return FALSE;
}

BOOL CMutex::Unlock()
{
	return ReleaseMutex(m_Mutex);
}

My program was crashing due to some sync issues. To test my mutex code I added some test commands into a sample program.
m_Mutex = new CMutex();
m_Mutex->Create();
if (TRUE == m_Mutex->Lock(50000))
{
	if (TRUE == m_Mutex->Lock(60000))
	{
		etc....
	}
}

I would expect this to lock as the mutex is acquired in the first lock, and will never be released, allowing the second lock to continue, however WAIT_OBJECT_0 is returned from each call to WaitForSingleObject Any help you can give would be great. All my research shows that I am doing things correctly. http://msdn.microsoft.com/en-us/library/ms686927(VS.85).aspx

Share this post


Link to post
Share on other sites
Advertisement
Hi Dave

Thanks for the reply. Prehaps I am testing from an incorrect point of view. I'll try and explain my real runtime condition for you. I am currently doing some work on procedural planets. I want the planet updating to take place on a different thread than the rendering.


void CPlanet::Render(CCamera* p_pCamera)
{
if (TRUE == m_Mutex->Lock(60000))
{
CDebug::Log("Debug.txt", "%d CPlanet::Render\n", GetCurrentThreadId());

CObject::StartRendering(p_pCamera);

if (NULL != m_pDetailTexture)
{
m_pDetailTexture->Bind(GL_TEXTURE1_ARB);

glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
glTexEnvi(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 2);
}

m_pCamera = p_pCamera;

CDebug::Log("Debug.txt", "%d CPlanet::Render FRONT\n", GetCurrentThreadId());
m_pFaces[FRONT].Render(p_pCamera);

CDebug::Log("Debug.txt", "%d CPlanet::Render RIGHT\n", GetCurrentThreadId());
m_pFaces

.Render(p_pCamera);

CDebug::Log("Debug.txt", "%d CPlanet::Render BACK\n", GetCurrentThreadId());
m_pFaces[BACK].Render(p_pCamera);

CDebug::Log("Debug.txt", "%d CPlanet::Render LEFT\n", GetCurrentThreadId());
m_pFaces

.Render(p_pCamera);

CDebug::Log("Debug.txt", "%d CPlanet::Render TOP\n", GetCurrentThreadId());
m_pFaces[TOP].Render(p_pCamera);

CDebug::Log("Debug.txt", "%d CPlanet::Render BOTTOM\n", GetCurrentThreadId());
m_pFaces[BOTTOM].Render(p_pCamera);

if (NULL != m_pDetailTexture)
m_pDetailTexture->Unbind(GL_TEXTURE1_ARB);

CObject::EndRendering(p_pCamera);

m_Mutex->Unlock();

CDebug::Log("Debug.txt", "%d CPlanet::Render Complete\n", GetCurrentThreadId());
}
}



The Planet Update Function is

void CPlanet::Update(CCamera* p_pCamera)
{
if (TRUE == m_Mutex->Lock(60000))
{
CDebug::Log("Debug.txt", "%d CPlanet::Update\n", GetCurrentThreadId());

m_pFaces[FRONT].Update(p_pCamera);
m_pFaces

.Update(p_pCamera);
m_pFaces[BACK].Update(p_pCamera);
m_pFaces

.Update(p_pCamera);
m_pFaces[TOP].Update(p_pCamera);
m_pFaces[BOTTOM].Update(p_pCamera);

m_Mutex->Unlock();

CDebug::Log("Debug.txt", "%d CPlanet::Update Complete\n", GetCurrentThreadId());
}
}



which is called by a seperate thread


DWORD WINAPI PlanetThread(LPVOID p_Parameter)
{
CPlanet* l_pPlanet = (CPlanet*)p_Parameter;

while(1)
{
l_pPlanet->Update(l_pPlanet->m_pCamera);
Sleep(50);
}

return 0;
}



With this setup I would hope that the system would lock and rendering/updating take place at seperate times, however the debug file shows...

2256 CPlanet::Update
1212 CPlanet::Render Complete
1212 CPlanet::Render
1212 CPlanet::Render FRONT
1212 CPlanetPatch::Render. Rendering NorthWest Child
2256 CPlanet::Update Complete
1212 CPlanetPatch::Render. Rendering Patch
...
..
.

How would I ensure that when the planet is updating that no rendering takes place. (Please note that this is not my ultimate goal. I want updating and rendering to take place at the same time, however certain sections need to be critical. Its just easier to explain and test in this form)

I have tried using CriticalSection however this also did not appear to work. Is this the right area?

Thanks

Share this post


Link to post
Share on other sites
Hmm, at first glance i can't see why that won't work. Have you tried using Critical Sections?

EDIT: Just read the end of your post.

Share this post


Link to post
Share on other sites
Hi Dave

I have tried Critical Section but get the same error as before. My Critical Section code is as follows


#ifndef DECADE_MUTEX_HEADER_H
#define DECADE_MUTEX_HEADER_H

#include <windows.h>

class CMutex
{
//Private Member Variables
private:

CRITICAL_SECTION m_Mutex;
char m_pszMutexName[256];

//Public Member Variables
public:

//Private Member Functions
private:

//Public Member Functions
public:

CMutex();
~CMutex();

void Create(char* p_pszName = NULL);
void Close();

BOOL Lock(int p_iTimeout = 1000);
BOOL Unlock();
};

#endif




#include "Mutex.h"
#include "Debug.h"

CMutex::CMutex()
{
}

CMutex::~CMutex()
{
Close();
}

void CMutex::Create(char* p_pszName)
{
memset(m_pszMutexName, 0x00, sizeof(char) * 256);
if (NULL != p_pszName)
strcpy_s(m_pszMutexName, 256, p_pszName);

InitializeCriticalSection(&m_Mutex);
}

void CMutex::Close()
{
DeleteCriticalSection(&m_Mutex);
}

BOOL CMutex::Lock(int p_iTimeout)
{
EnterCriticalSection(&m_Mutex);
CDebug::Log("Debug.txt", "Mutex %s Locked by Thread %d\n", this->m_pszMutexName, GetCurrentThreadId());
return TRUE;
}

BOOL CMutex::Unlock()
{
LeaveCriticalSection(&m_Mutex);
CDebug::Log("Debug.txt", "Mutex %s Unlocked by Thread %d\n", this->m_pszMutexName, GetCurrentThreadId());
return TRUE;
}



And again the Debug shows that both threads are entering the Critical Section at the same time

Mutex Planet Locked by Thread 1176
1176 CPlanet::Update
Mutex Planet Locked by Thread 2268
2268 CPlanet::Render
2268 CPlanet::Render FRONT
2268 CPlanetPatch::Render. Rendering NorthWest Child
2268 CPlanetPatch::Render. Rendering Patch
...
..
.

Share this post


Link to post
Share on other sites
Looks to me like your Update() is finishing before Render() is called. The log looks correct to me.

Share this post


Link to post
Share on other sites
I would advise using a critical section rather than mutex in this case. A mutex is typically used when synchronising between one or more processes, they require a slow transition to kernel mode in order to aqcuire the lock. A critical section is used for synchronizing one or more threads within the same process, and they do not require a transition into kernel mode to acquire the lock. Acquiring a critical section lock is often at least an order of magnitude quicker than acquiring a mutex lock.

As your code shows, one other notable difference between a mutex and a critical section is that you cannot specify a timeout for a critical section. Your timeout code raises a few eyebrows with me anyway though. Why would you want to wait for 60 seconds for a lock and then stop waiting?

I also see that you are releasing the locks in your code before you output the "function complete" messages. That could cause some strangeness in your output. You may get a "CPlanet::Update Complete" message in the middle of your rendering update messages, for example.

Other than that I cannot see how the same critical section could become locked by two different threads at the same time. Some potential problems that come to mind are; the two threads are not locking the same critical section(you have somehow managed to create two different critical sections); the debug output is broken and the code is actually doing what you expect; your lock is not properly initialized in some way; or the code you are showing us is not complete.

Good luck. :)

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!