 
  
I was recently faced with the task of adding support for WIN32 threads in my 3d engine. After
scouring the web for ideas, I finally came up with this simple solution. Ironically the thread
class that I finally wrote was inspired by Java's Thread class.
I have included a zip file containing the thread class, a simple WIN32 console test program,
and VC 6 workspace file.
 | 
 
 
 
Currently browsing [win32threads.zip] (4,786 bytes) - [threads/thread.hpp] - (3,593 bytes)
 
 //------------------------------------------------------------------------
// File    : thread.hpp
// Author  : David Poon
// Written : 6 May 2001
// 
// WIN32 Thread class.
//
// Copyright (C) 2001 David Poon
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License 
// along with this program; if not, write to the Free Software Foundation
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//------------------------------------------------------------------------
#ifndef WIN32_THREAD_CLASS_HPP
#define WIN32_THREAD_CLASS_HPP
  #include <windows.h>
#include <process.h>
  //------------------------------------------------------------------------
// Class   : Mutex
// Extends : none
//
// A Mutex allows threads mutually exclusive access to a resource.
//------------------------------------------------------------------------
class Mutex
{
public:
	Mutex() {InitializeCriticalSection(&m_mutex);}
	~Mutex() {DeleteCriticalSection(&m_mutex);}
  	void acquire() {EnterCriticalSection(&m_mutex);}
	void release() {LeaveCriticalSection(&m_mutex);}
  private:
	CRITICAL_SECTION m_mutex;
};
  //------------------------------------------------------------------------
// Class   : Lock
// Extends : none
//
// A Lock provides a safe way to acquire and release a Mutex. The Mutex 
// is acquired when the Lock it created. The Mutex is released when the
// Lock goes out of scope.
//------------------------------------------------------------------------
class Lock
{
public:
	Lock(Mutex &mutex) : m_mutex(mutex) {m_mutex.acquire();}
	~Lock() {m_mutex.release();}
  private:
	Mutex &m_mutex;
};
  //------------------------------------------------------------------------
// Class   : Win32Thread
// Extends : none
//
// WIN32 thread class. The Win32Thread is always created in a suspended
// state. The thread is not running until start() is called. If zero is
// used as the stack size of the new thread, then Windows will use the
// stack size of the main thread.
//
// To create your own thread, subclass Win32Thread and provide an
// implementation for the run() method. If you want to give other threads
// the ability to cleanly shutdown your thread (recommended), then your
// thread's run() method should periodically call canRun() to check if 
// another thread has made a requested to shutdown your thread. canRun()
// will return false if another thread has requested that your thread
// shutdown.
//------------------------------------------------------------------------
class Win32Thread
{
public:
	Win32Thread();
	virtual ~Win32Thread();
  	bool create(unsigned int stackSize = 0);
	unsigned int threadId() const;
	void start();
	void join();
  	void resume();
	void suspend();
	void shutdown();
	
protected:
	bool canRun();
	virtual void run() = 0;
  private:
	static unsigned int __stdcall threadFunc(void *args);
	
	HANDLE m_hThread;
	unsigned int m_threadId;
	volatile bool m_canRun;
	volatile bool m_suspended;
	Mutex m_mutex;
};
  #endif   |  
  
 | 
 
  
Currently browsing [win32threads.zip] (4,786 bytes) - [threads/thread.cpp] - (2,493 bytes)
 
 //------------------------------------------------------------------------
// File    : thread.cpp
// Author  : David Poon
// Written : 6 May 2001
// 
// Implementation file for the threading classes defined in thread.hpp
//
// Copyright (C) 2001 David Poon
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of 
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 
// General Public License for more details.
//
// You should have received a copy of the GNU General Public License 
// along with this program; if not, write to the Free Software Foundation
// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//------------------------------------------------------------------------
#include "thread.hpp"
  Win32Thread::Win32Thread()
{
	m_hThread = 0;
	m_threadId = 0;
	m_canRun = true;
	m_suspended = true;
}
  Win32Thread::~Win32Thread()
{
	if (m_hThread)
		CloseHandle(m_hThread);
}
  bool Win32Thread::canRun()
{
	Lock guard(m_mutex);
	return m_canRun;
}
  bool Win32Thread::create(unsigned int stackSize)
{
	m_hThread = reinterpret_cast<HANDLE>(_beginthreadex(0, stackSize, 
		threadFunc, this, CREATE_SUSPENDED, &m_threadId));
	
	if (m_hThread)
		return true;
	
	return false;
}
  void Win32Thread::join()
{
	WaitForSingleObject(m_hThread, INFINITE);
}
  void Win32Thread::resume()
{
	if (m_suspended)
	{
		Lock guard(m_mutex);
		
		if (m_suspended)
		{
			ResumeThread(m_hThread);
			m_suspended = false;
		}
	}
}
  void Win32Thread::shutdown()
{
	if (m_canRun)
	{
		Lock guard(m_mutex);
  		if (m_canRun)
			m_canRun = false;
  		resume();
	}
}
  void Win32Thread::start()
{
	resume();
}
  void Win32Thread::suspend()
{
	if (!m_suspended)
	{
		Lock guard(m_mutex);
  		if (!m_suspended)
		{
			SuspendThread(m_hThread);
			m_suspended = true;
		}
	}
}
  unsigned int Win32Thread::threadId() const
{
	return m_threadId;
}
  unsigned int __stdcall Win32Thread::threadFunc(void *args)
{
	Win32Thread *pThread = reinterpret_cast<Win32Thread*>(args);
	
	if (pThread)
		pThread->run();
  	_endthreadex(0);
	return 0;
}   |  
  
 | 
 
  
Currently browsing [win32threads.zip] (4,786 bytes) - [threads/main.cpp] - (1,217 bytes)
 
 #include <conio.h>
#include "thread.hpp"
  class Display : public Win32Thread
{
public:
	Display() : Win32Thread() {}
	~Display() {}
  private:
	void run();
};
  void Display::run()
{
	while (canRun())
	{
		Sleep(500);
		_putch('.');
	}
  	_putch('*');
}
  class Input : public Win32Thread
{
public:
	Input() : Win32Thread() {}
	~Input() {}
  private:
	void run();
	Display m_display;
};
  void Input::run()
{
	// Start the Display thread.
	if (m_display.create())
		m_display.start();
	else
		return;
  	bool quit = false;
  	while (!quit)
	{
		if (_kbhit())
		{
			switch (_getch())
			{
			default:
				break;
  			// Suspend Display thread
			case 's':
			case 'S':
				m_display.suspend();
				break;
  			// Resume Display thread
			case 'r':
			case 'R':
				m_display.resume();
				break;
  			// Shutdown Input and Display threads.
			case 'q':
			case 'Q':
			case 27:
				m_display.shutdown();
				m_display.join();
				quit = true;
				break;
			}
		}
	}
}
  int main()
{
	Input input;
  	if (input.create())
	{
		input.start();
		input.join();
	}
  	_cputs("\r\nmain thread has now joined with input thread\r\n");
	return 0;
}
   |  
  
 | 
 
 
 
The zip file viewer built into the Developer Toolbox made use
of the zlib library, as well as the zlibdll source additions.
 
 
 |