Baby Steps

Published October 07, 2008
Advertisement
Holy crap, an update! I haven't had much to say lately because work has been draining my urge to work on personal projects, but I have a few things in the works that may or may not see the light of day.

So, the subject of today's entry is multithreading. Multithreading is no longer the wave of the future, it's here and it's not going away. As such, I figured I should learn a thing or two about it. This is something I've wanted to do for a while, but have been terribly lazy about. And, you know, it's very relevant to work, so that's a plus.

That all said, I spent an hour tonight hammering out a very basic introduction for myself into the world of threading. Nothing terribly special, it's just one thread writing to a queue while another reads from it. I'll let the code speak for itself, critique it as you will.

Mutex.h
#ifndef MUTEX_H#define MUTEX_H#include #define LOCK(hLock, timeout) 	{ 	thread::Mutex _lock(hLock, timeout);#define SAFE_LOCK(hLock, timeout) 	try { 	thread::Mutex _lock(hLock, timeout);#define UNLOCK 	}typedef void* HANDLE;namespace thread{	class WaitAbandonedException : public std::exception	{	public:		WaitAbandonedException() throw() {}		WaitAbandonedException(const WaitAbandonedException& rhs) throw() {}		WaitAbandonedException& operator=(const WaitAbandonedException& rhs) throw() {}		virtual ~WaitAbandonedException() throw() {}		virtual const char *what() const throw() {return "Wait Abandoned";}	};	class WaitTimeoutException : public std::exception	{	public:		WaitTimeoutException() throw() {}		WaitTimeoutException(const WaitTimeoutException& rhs) throw() {}		WaitTimeoutException& operator=(const WaitTimeoutException& rhs) throw() {}		virtual ~WaitTimeoutException() throw() {}		virtual const char *what() const throw() {return "Wait Timeout";}	};		class Mutex	{	public:		Mutex( HANDLE hLock, DWORD timeout);		Mutex( const Mutex& copy );		Mutex &operator=(const Mutex &rhs);		~Mutex();		bool Locked() {return m_IsLocked;}	private:		HANDLE			m_Lock;		//mutable locked state because it will be changed on copy and assignment when ownership is passed		mutable bool	m_IsLocked;	};}#endif


Mutex.cpp
#include #include "Mutex.h"thread::Mutex::Mutex( HANDLE hLock, DWORD timeout ):	m_Lock(hLock),m_IsLocked(false){	//aquire lock on construction	DWORD Ret = WaitForSingleObject(m_Lock,					timeout);	switch (Ret)	{	case WAIT_OBJECT_0:		m_IsLocked = true;		break;	case WAIT_ABANDONED:		throw *(new thread::WaitAbandonedException);		break;	case WAIT_TIMEOUT:		throw *(new thread::WaitTimeoutException);		break;	default:		//unkown error, just bail		throw;		break;	}}thread::Mutex::Mutex(const thread::Mutex& copy){	*this = copy;}thread::Mutex& thread::Mutex::operator=(const thread::Mutex &rhs){	//release any existing lock	if (m_IsLocked)	{		ReleaseMutex(m_Lock);	}	m_Lock = rhs.m_Lock;	m_IsLocked = rhs.m_IsLocked;	//take ownership of copied mutex	rhs.m_IsLocked = false;	return *this;}thread::Mutex::~Mutex(){	if (m_IsLocked)	{		ReleaseMutex(m_Lock);	}}


thread.h
#ifndef THREAD_H#define THREAD_H#include extern HANDLE g_Mutex;namespace thread{	DWORD WINAPI Func(LPVOID lParam);}#endif


thread.cpp
#include "thread.h"#include "Mutex.h"#include #include #include extern std::queue<int> g_Queue;DWORD WINAPI thread::Func(LPVOID /*lParam*/){	while(TRUE)	{		SAFE_LOCK(g_Mutex, INFINITE)			while (!g_Queue.empty())			{				if (g_Queue.front() == -1)				{					return TRUE;				}				std::cout << "Thread two reading " << g_Queue.front() << " from queue.\n";				g_Queue.pop();			}		UNLOCK		catch (std::exception &e)		{			std::cout << "Caught exception in thread 2: " << e.what() << "\n";			delete &e		}	}	return TRUE;}


main.cpp
#include #include #include #include "thread.h"#include "Mutex.h"HANDLE g_Mutex;std::queue<int> g_Queue;void FillQueue();int main(){	g_Mutex = CreateMutex(	NULL,				FALSE,				NULL );	DWORD threadID;	HANDLE hThread = CreateThread(	NULL,					0,					thread::Func,					NULL,					0,					&threadID );	FillQueue();	WaitForSingleObject(hThread,			    INFINITE);	CloseHandle(hThread);	CloseHandle(g_Mutex);	return 0;}void FillQueue(){	for (int i = 0; i < 100; ++i)	{		SAFE_LOCK(g_Mutex, INFINITE)			std::cout << "Thread one adding " << i << " to the queue.\n";			g_Queue.push(i);		UNLOCK		catch (std::exception &e)		{			std::cout << "Caught exception in thread 1: " << e.what() << "\n";			delete &e		}	}	g_Queue.push(-1);	return;}


'Til next time!
Previous Entry ...
Next Entry /facepalm
0 likes 1 comments

Comments

rip-off
If I were you, I wouldn't copy construct any variables of type Mutex soon [smile]

In fact, I don't really believe that you can have sane copy semantics on a Mutex. I would probably just make them non-copyable.
October 07, 2008 07:30 AM
You must log in to join the conversation.
Don't have a GameDev.net account? Sign up!
Advertisement

Latest Entries

/facepalm

1665 views

Baby Steps

1234 views

...

720 views

Stuff

1266 views

Productivity++

1159 views

Rock Band FTW

1194 views

Seattle Opera

1237 views

Christ

1161 views

I maek gaem!

1138 views
Advertisement