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.
|