Jump to content
  • Advertisement

Archived

This topic is now archived and is closed to further replies.

Zefrieg

Free Code (Easy Multithreading)

This topic is 5099 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I''ve been playing with threads, and I was able to produce an easy way to encapsulate thread making into an easy to use class. I will post the code and explain: Thread.h
#ifndef NETWORK_THREAD_H
#define NETWORK_THREAD_H

#pragma once

// Includes /////////////////////////////

#include <windows.h>

// Namespace ////////////////////////////

namespace Network
{

// Class ////////////////////////////////

class Thread
{
protected:
	HANDLE m_handle;
protected:
	friend void WINAPI ThreadFunc(Thread* _thread);
public:
	// virtual functions

	virtual void Create(LPSECURITY_ATTRIBUTES _security, SIZE_T _stackSize, DWORD _creationFlags); 
	virtual void Run() = 0;

	// Constructor/Destructor

	Thread(void);
	~Thread(void);
};

}

#endif // NETWORK_THREAD_H

This is the basic Thread class that all threaded classes will inherit from. There is a friend function named, ThreadFunc(), which accepts a pointer to a Thread as a parameter. The Create() function accepts parameters similar to the CreateThread() Win32 function. There is a pure virtual function named Run() which will be used to implement the threaded routine. The m_handle member data acts has a handle to the thread created by Create(). Thread.cpp
#include ".\thread.h"

namespace Network
{

Thread::Thread(void)
{
	m_handle = 0;
}

Thread::~Thread(void)
{
	this->Close();
}

void WINAPI ThreadFunc(Thread* thread)
{
	while(1)
	{
		thread->Run();
	}
}

void Thread::Create(LPSECURITY_ATTRIBUTES _security, SIZE_T _stackSize, DWORD _creationFlags)
{
	m_handle = CreateThread(_security, _stackSize, (LPTHREAD_START_ROUTINE)ThreadFunc, this, _creationFlags, 0);
}

void Thread::Close()
{
	if(m_handle)
	{
		CloseHandle(m_handle);
		m_handle = 0;
	}
}

}
Notice the definition of the ThreadFunc() function. It merely calls the pure virtual function Run() that will be defined by inherited classes. The Create() function is merely a wrapper for CreateThread(). The data members included are pretty standard, but notice the this pointer that is used as the parameter for the thread. This will be used to call the Run function of the inherited classes. ServerThread.h
#ifndef NETWORK_SERVERTHREAD_H
#define NETWORK_SERVERTHREAD_H

#pragma once

// Includes ///////////////////////////

#include <iostream>
#include "Thread.h"

// Namespace //////////////////////////

namespace Network
{

// Class //////////////////////////////

class ServerThread : public Thread 
{
public:
	int number;
public:
	// Thread Functions

	void Run(); 

	// Constructor/Destructor

	ServerThread(void);
	~ServerThread(void);
};

}

#endif // NEWORK_SERVERTHREAD_H

The ServerThread class inherited the Thread class. It only includes an int named number for demonstrational purposes. The Run() function must be included in the ServerThread class. Pretty simple stuff. ServerThread.cpp
#include ".\serverthread.h"

namespace Network
{

ServerThread::ServerThread(void)
{
}

ServerThread::~ServerThread(void)
{
}

void ServerThread::Run()
{
	std::cout << "(" << number << ")" << "Hi" << std::endl;
}

}
There you go. You only have to fill in the Run() function with whatever you want to be threaded. Main.cpp
// Includes ///////////////////////////////

#include <iostream>
#include "ServerThread.h"

// Main ///////////////////////////////////

int main()
{
	Network::ServerThread thread;
	Network::ServerThread thread2;

	thread.number = 1;
	thread2.number = 2;

	thread.Create(0, 0, 0);
	thread2.Create(0, 0, 0);

	while(1)
	{
		std::cout << "HI!" << std::endl;
	}

	return 0;
}
Here is a little sample main() function that demonstrates the threaded application. The program will switch between outputting "HI"!, "(1)Hi", and "(2)Hi". Though where and when it switches is random. It does not wait for one output statement to finish before switching threads. Though, when it comes back to the unfinished thread, it will start back where it left off.

Share this post


Link to post
Share on other sites
Advertisement
Actually, I need to make a change. Instead of declaring the base class Run() function as a pure virtual. It should be declared as just a virtual function in the Thread.h like this:

virtual void Run();

And be declared as this in the Thread.cpp file:

void Thread::Run()
{

}

I did not notice it before, but the destructers would be called for the inherited class while the thread was still being ran from the base class pointer. This would revert the friend function, ThreadFunc(), into trying to call the pure virtual function Run() in the base class. This would create an error. By making this change, then the ThreadFunc() will just call a blank function until the base class is destroyed.

Share this post


Link to post
Share on other sites
Guest Anonymous Poster
I think you should read a little bit more about virtuality...

The point of inheritance is to be able to call a specialized function ( from a derived class ) from a base class pointer...

Remember :

class shape
{
public:
virtual void draw() = 0;
}

class circle
{
public:
virtual void draw();
}

class square
{
public:
virtual void draw();
}

void main (void)
{
shape *a = new circle;
shape *b = new square;

a->draw();
b->draw();

delete (a);
delete (b);
}

Share this post


Link to post
Share on other sites
Spout your dribble elsewhere, Anonymous Poster. If you don''t know the problems associated with making a CreateThread wrapper, then don''t assume that I know nothing about virtual functions.

This is a workaround from the fact that because of the added "this" pointer associated with member class functions, they are not compatible with regular function pointers. This workaround allows a person, with the use of a BASE CLASS POINTER AND AN INHERITED VIRTUAL FUNCTION, bind a derived class member function to the thread. Not only that, but does it in a way that makes creating threads a no-brainer.

Share this post


Link to post
Share on other sites
I hope not to sounbd mean, but this is a very common way to encapsulate a Thread object. I wrote mine 2 years ago and it's quite the same than yours... I can't see another way to do it... By the way I guess that the MFC's CThread (even for some people not a reference) is doing the same in some way...

By the way if you're interested in some improvements... I can post mine...

[edited by - werbfred on June 8, 2004 6:50:47 AM]

Share this post


Link to post
Share on other sites
Why not make the Thread take either a member function or a free-standing function to call? Inheriting from a class to use it is laborous. This is what the AP was implying -- it is a bit of an OO abuse to inherit from Thread just to use the thing.

Additionally the ThreadProc could be hidden in the implementation file in an anonymous namespace. I don''t see the point of having a Create() member function -- it is just one thing for me to forget to call when the constructor or Run() could do it. There is no error checking on CreateThread() -- consider throwing an exception. Default arguments could be used to simplify normal uses of the code. _beginthreadex() should be used instead of CreateThread(), especially around C++. The instance pointer should be explicitly casted so it compiles fine on level 4 warnings.

And Stroustrup calls denoting blank parameter lists with void an abomination.

Thats all I can think of for now.

Share this post


Link to post
Share on other sites
I like the way Java does it. You can either inherit from Thread and define the run method, or create a Thread and give it a Runnable object to use. Then it''s up to the user to decide if they want to inherit or not.

As for the destruction problem, IMHO the user should be stopping the thread before destroying the thread object. Either in their derived class destructor or through a stop method.

Share this post


Link to post
Share on other sites
quote:
Original post by parla
Why don''t you use boost::thread and save yourself the hassle?


Yes, why dont we all just stop coding, and start using other people''s s**t?

argh, makes me mad when people instead of suporting you for doing the hard thing, slam you with "why didnt you use the ****"....

lame atitude...

Salsa cooked it, your eyes eat it!
[Hugo Ferreira][Positronic Dreams][Colibri 3D Engine][Entropy HL2 MOD][My DevDiary]
[Yann L.][Enginuity] [Penny Arcade] [MSDN][VS RoadMap][Humus][BSPs][UGP][NeHe]
"our stupidity allways comes back to bite us in the ass... in a white-shark sort of way..." - Prozak

Share this post


Link to post
Share on other sites
Yes, a very common way to do things, sorry nothing too original here, but an adequate job nonetheless.

Here is my threading library to give you other ideas: Click Here. It''s portable for Win32 and Posix, provides you with a base class for thread extension and provides a Simple Thread class that allows you to do one-shot threads that fire off a function where you don''t want to create a whole new class for it. It also provides a Simple Mutex class (again Win32/Posix flavours).

Any comments appreciated.

Regards,
Jeff


[ CodeDread ]

Share this post


Link to post
Share on other sites

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

Participate in the game development conversation and more when you create an account on GameDev.net!

Sign me up!