This section of the archives stores flipcode's complete Developer Toolbox collection, featuring a variety of mini-articles and source code contributions from our readers.

| Simple Win32 Thread Class Submitted by David Poon

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.

Copyright 1999-2008 (C) FLIPCODE.COM and/or the original content author(s). All rights reserved.
Please read our Terms, Conditions, and Privacy information.