Sign in to follow this  
Xeile

Thread Synchronisation problems

Recommended Posts

Platform: WindowsXP Development Program: Visual Studio .NET 2003 Application type: Win32 Hello all, I got a class who got his own thread running, to do some on-goinging processing (keyboard and mouse). At some point when I want exit my program, the thread of course has to exit too. I'm trying to do this with the help of mutexes. First the baseclass looks the following.
typedef enum 
{
	CTL_KEYBOARD, 
	CTL_MOUSE, 
}INPUT_CONTROL, *PINPUT_CONTROL;

class __declspec(dllexport) CObjectInput
{
public:
	CObjectInput(HWND hWnd, INPUT_CONTROL Control);
	~CObjectInput();

	LPDIRECTINPUT8			GetObject();
	LPDIRECTINPUTDEVICE8		GetDevice();
	void				Acquire();
	void				Unacquire();
	virtual void			Process() = 0;
	
private:
	HANDLE				Occupied;
	LPDIRECTINPUT8			Object;
	LPDIRECTINPUTDEVICE8		Device;
	HANDLE				ThreadHandle;
	static DWORD WINAPI		ThreadProc(LPVOID Parameters);
};




Constructor, Destructor and ThreadProc
CObjectInput::CObjectInput(HWND hWnd, INPUT_CONTROL Control)
:	Object(NULL), Device(NULL) 
{
	Occupied = CreateMutex(NULL, false, "Occupied"); // Mutex starting in signaled state, according to documentation
	/* Lots of uninteresting inits here */
	ThreadHandle = CreateThread(NULL, 0, ThreadProc, this, 0, 0); // Immediate start of thread
}

CObjectInput::~CObjectInput()
{
	WaitForSingleObject(Occupied, INFINITE);
	CloseHandle(Occupied);
	if(Object)
	{
		if(Device)
		{
			Device->Release();
		}
		Object->Release();
	}
}

DWORD CObjectInput::ThreadProc(LPVOID Parameters)
{
	CObjectInput* Myself = (CObjectInput*)Parameters;
	while(1)
	{
		switch(WaitForSingleObject(Myself->Occupied, INFINITE))
		{
			case WAIT_OBJECT_0:
				Myself->Process(); // Function that need some resources in the baseclass
				ReleaseMutex(Myself->Occupied);
				break;
			case WAIT_FAILED:
			case WAIT_ABANDONED:
				ExitThread(1);
				break;
			default:
				ExitThread(1);
				break;
				
		}
	}
	return 0;
}




The constructor and destructor are always called in the process execution, so no different thread is executing them. When exiting my program, I sometimes get the following Runtime - error (seen in the image below). Afbreken = Abort, Opnieuw = Try Again, Negeren = Ignore It is being triggered by calling the Myself->Process() function, in the thread execution. That it suddenly becomes an pure virtual function is caused by the class destruction. I am trying to solve this problem by using a mutex. But is not working correctly. I hoped it would work like the following (this is the current situation):

<Thread 0 (Process itself)>        <Thread 1>
Run Program                        Run Threadfunction

[User pressed 'ESC']
Delete Keyboard                   Run Threadfunction
Baseclass Waits for mutex          Run Threadfunction
...                                Threadfunction waits for mutex
Baseclass retrieves mutex          Threadfunction waits for mutex
Baseclass destroys and closes      Threadfunction exits, waiting for mutex
mutex                              resulted into abandoned





Sometimes this works and sometimes it doesn't. I cannot explain why this happens. According to documentation, only one thread can own the mutex. Both threads are waiting forever (INFINITE milliseconds). See Remarks for more info on Mutexes and WaitForSingleObject Does anyone see what I am doing wrong here? If you need more info, don't hasitate to ask. Best regards, Xeile [Edited by - Xeile on April 22, 2006 8:58:15 AM]

Share this post


Link to post
Share on other sites
In C++ an object is considered to be destroyed as soon as execution enters the destructor. Objects in C++ are also destroyed outside in, and so by the time the base class destructor is called the derived class destructor will already have been called. This means by the time the base class destructor is called your vtable is already wrong.

Now if the objects derived class destructor is called in between the ThreadProc thread aquiring the mutex and calling the virtual function, then you will get the error you describe. The locks do not protect that from happening.

Share this post


Link to post
Share on other sites
It's a really good idea to let your threads terminate properly, and wait on each other (but don't use mutexes for this!). Use a proper platform API mechanism (WaitThread) to ensure a thread has terminated before thinking it has.

I usually trigger thread termination by setting a flag in an object associated with the thread. The thread itself sees this and exits it's ThreadMain, allowing the thread to die gracefully.

This is a neat way of doing this without resorting to signals / events and cleaning up undue mess from premature terminations.

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this