5 – Thread Pool Step 3: Enter Thread Pool

Welcome to the big sha-bang. The KMThreadPool class is the container for all the threads and all the tasks. There’s only a few functions we’ll need outside of the library in order to use the pool properly, but for now, lets look at what members this class contains:

private:
	KMQueue<KMTask*>	m_qtaskList;
	vector<KMThread*>	m_vthreads;
	unsigned int		m_nactive;
	volatile bool m_bprocess;
	//Singleton
	static KMThreadpool m_instance;

So we have our m_qtaskList and m_vthreads – pretty self-explanitory, then we have a count of the number of active threads (this will become relative in a moment), and then — Hey! There’s that volatile jerk I talked about on the last page! Well, he comes in handy here because that bool is very important; he’s used to indicate that the thread pool is actively delegating tasks to the threads (so you can delay the start of or suspend task processing). Then we have our static Singleton instance. We only ever need 1 thread pool, right?

Here, we have the primary functions you’ll need to actually run the thread pool. There is no update function, just start it and stop it. Easy as Π.

void Initialize(unsigned int uiTryMinNumThreads,
		unsigned int uiTryMaxNumThreads);
void Shutdown();
void AddTask(KMTaskFunc task, IKMTaskData* data);
void BeginProcessing();
void StopProcessing();

These functions are what you’re going to use to make your program interact with the thread pool.

Initialize()

First off is Initialize(). Some of you are looking at it, and are wondering why I have “uiTryMinNumThreads” and “uiTryMaxNumThreads” Well, the reason is simple: With uiTryMinNumThreads, that’s the lowest number of threads your program will try to create. If, for some reason, the creation fails on creating the minimum, the thread pool will not initialize. uiTryMaxNumThreads is also the same logic, however, if the computer cannot create the exact number of max threads, that’s OK – We still have the minimum.

void KMThreadpool::Initialize(unsigned int uiTryMinNumThreads,
				unsigned int uiTryMaxNumThreads)
{
	unsigned int i;
	//Create the threads
	m_vthreads.assign(uiTryMinNumThreads, NULL);

	//Initialize the min number of threads
	for(i = 0; i < uiTryMinNumThreads; ++i)
 	{
 		m_vthreads[i] = new KMThread();
 		m_vthreads[i]->Begin();
		if(m_vthreads[i]->isRunning())
		{
			++m_nactive;
		}
	}
	//Try to initialize the max number of threads. If one fails,
	//we stop.
	for(i = uiTryMinNumThreads; i < uiTryMaxNumThreads; ++i)
 	{
 		KMThread* trythread = new KMThread();
 		trythread->Begin();
		if(trythread->isRunning())
		{
			m_vthreads.push_back(trythread);
			++m_nactive;
		}
		else
		{
			delete trythread;
			break;
		}
	}
}

Note: A good portion of this code is meant for educational purposes – so as not to overly confuse people, a lot of error-checking has been omitted. You can add it if you’d like – it’s not all that difficult.

BeginProcessing() & StopProcessing()

Lets take a moment to look at these functions. Mainly all they do is toggle the m_bprocess bool. After the threads finish their current task, before they go and grab a new task from they queue, they check the thread pools’ m_bprocess bool, and if it’s false, they sit and wait until the thread pool starts up again. Easy, but very important. These functions allow you to start the task processing when you’re ready to start processing. You could load up the thread pool with 3000 tasks and the threads won’t touch one until BeginProcessing() is called.

Shutdown()

The shutdown is simple. Stop the threads, clean the task memory, then clean the thread memory. not much else to it.

void KMThreadpool::Shutdown()
{
	KMTask* deltask;
	KMThread* delthread;
	// Stop the delegation of tasks
	if(m_bprocess != false)
	{
		m_bprocess = false;
	}
	//Clear the threads
	while(!m_vthreads.empty())
	{
		delthread = m_vthreads.back();
		m_vthreads.pop_back();
		delthread->End();
		delete delthread;
	}
	//Clear the tasks
	while(!m_qtaskList.empty())
	{
		//deltask = m_qtaskList.front();
		deltask = m_qtaskList.pop();
		delete deltask;
	}
}

AddTask()

This one is also pretty simple as well. When you pass in a function pointer and a pointer to a child of IKMTaskData, this function puts it into the KMTask container object, and adds it to the queue.

void KMThreadpool::AddTask(KMTaskFunc task, IKMTaskData* data)
{
	KMTask* newTask = new KMTask(task,data);
	m_qtaskList.push(newTask);
}

There you have it. That pretty much covers the thread pool. Congratulations!

>> Next, Step 4: How to Use >>

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s