Multi-core processing?

The Partridge Family were neither partridges nor a family. Discuss.
Post Reply
Tommy
Posts: 11
Joined: December 1st, 2012, 7:14 am

Multi-core processing?

Post by Tommy » March 27th, 2013, 5:35 am

My program can be easily split into completely separate tasks without any memory collisions etc.

How can I assign those separate tasks (blocks of code) to the different cores?

Is there an easy way?

Paradox
Posts: 22
Joined: July 14th, 2012, 4:11 pm

Re: Multi-core processing?

Post by Paradox » April 15th, 2013, 12:21 am

Yes, there is. But it's notoriously tricky.
Concurrency is one of the hardest subjects to truly master, or so I've been told, as I haven't come close to mastering it myself :D .

For my own independent project (Outside of Chili's DXFramework), I've written this class:
For compatibility reasons, I chose not to use std::thread, because still many compilers don't support it, including MSVC 2010. As an alternative, I used Boost::thread, which you need to download and build. In fact, std::thread is based off of boost::thread, it's predecessor, so if you would like to avoid Boost, It shouldn't be too difficult to convert this.

The header:

Code: Select all

#pragma once

#include <boost/thread/thread.hpp>

#include <assert.h>
#include <crtdbg.h>
#include <Windows.h>

#include "Defines.h"

class ThreadBase
{
public:
	ThreadBase();
	virtual ~ThreadBase();

	virtual void ThreadDoUserExec() = 0; 

	void ThreadMain();

	uatomic Signals[200]; //uatomic happens to be my typedef for volatile signed int
private:
	boost::thread Internal_thread;
};
And the implementation:

Code: Select all

#include "ThreadBase.h"

ThreadBase::ThreadBase()
{
	Internal_thread = boost::thread(&ThreadBase::ThreadMain, this);
	memset( (void *)Signals, NULL, sizeof(uatomic) * 200);
}


ThreadBase::~ThreadBase()
{
	Internal_thread.interrupt();
	assert( (Internal_thread.joinable() ) );
	Internal_thread.join();
}

void ThreadBase::ThreadMain()
{
	try
	{
		ThreadDoUserExec();
	}
	catch(boost::thread_interrupted& Interruption)
	{
		(Interruption);
		_RPT1(_CRT_WARN, "Thread %d is interrupt. Exception: "
			"boost::thread_interrupted Interruption thrown; \n\t"
			"void ThreadBase::ThreadMain()\n", Interruption);
	}
	catch(std::exception& STDExcept)
	{
		(STDExcept);
		_RPT1(_CRT_WARN, "Thread %d has thrown. Exception: "
			"std::exception STDExcept thrown;\n \t"
			"void ThreadBase::ThreadMain() \n",STDExcept);
	}
}
This has the benefit of forcing destruction of the thread once it leaves scope, which removes one of the notoriously fickle aspects of concurrent programs.

Obviously this is abstract and requires the user to derive a new class implementing "void ThreadDoUserExec()", which will actually perform the operation you wish the function to do. The new thread will execute while the parent continues along.

That's actually what happens in my game. Because the timers I wrote always return, the thread spins, continually rendering and updating, until the message-pump (in the main thread) sets the quit-flag.

A simple implementation of this class might look like this:

Code: Select all

#pragma once

#include "ThreadBase.h"
#include "Game.h"
#include "IntervalCallTimer.h"

class GameThread : public ThreadBase
{
public:
	GameThread(Game * GamePtr);
	~GameThread();
	void ThreadDoUserExec();

private:
	Game * GamePtr;

};
And the implementation:

Code: Select all

#include "GameThread.h"
GameThread::GameThread(GAME_OBJ_ * GamePtr)
		:
	GamePtr(GamePtr)
{
	
}

GameThread::~GameThread()
{

}

void GameThread::ThreadDoUserExec()
{
	IntervalCallTimer Tick(GamePtr->Tick_GAME, BPS_TO_MILLIS(30) );
	IntervalCallTimer Display(GamePtr->Display_GAME, NO_INTERVAL );
	while (!Signals[Thread_Signal_Quit])
	{
		Tick.CallIfReady();
		Display.CallIfReady();
	}
}
This is all well and good, until it becomes necessary to pass information between threads. The same rules still apply as do in normal C++, but because the multiple threads may grab their time-slice at any time they choose, (even in multiple-core systems) data race becomes a very real possibility, and will result in seemingly random, non-reproducible bugs with no evident cause. When you go to share data between threads, you must ensure that either:
The write or read is atomic (only takes a single operation, so there's no possibility of the other thread reading a half-complete operation), or
The write or read is ensured to be complete before control is transferred.

The first option is used here with the signals[200] array; reads and writes of 32-bit ints are atomic on most architectures.

The second option generally requires locks, which prevent another thread from taking control until the lock releases. Boost::mutex (#include <boost/thread/mutex>) does a good job. When a thread needs to read/write data across threads, that portion of code is called a "critical section", and should be locked until the necessary read-write is complete, at which case, the lock needs to be released.

To be honest, unless there's a really strong need for it, you shouldn't use concurrency at all. I made this because I was curious (Yes!) and it allows a somewhat elegant way to keep the game moving at a constant rate, independent of hardware while still running the Windows message loop.
Of course, nobody ever learned anything by not trying, so please feel free to ask and experiment.

Boost:http://www.boost.org/
Information on locking and synchronization: http://www.boost.org/doc/libs/1_49_0/do ... ation.html
Getting Boost::thread working: http://www.boost.org/doc/libs/1_53_0/mo ... st-library

You'll want to follow step 5.2 once you download the libraries. The installers referenced are no longer present. If for some reason 5.2 won't work for you, you'll have to do it the hard way. :(

Good luck!

NaturalDemon
Posts: 97
Joined: October 28th, 2012, 8:28 pm

Re: Multi-core processing?

Post by NaturalDemon » April 18th, 2013, 10:46 pm


blueyeredragon
Posts: 12
Joined: June 20th, 2012, 7:29 pm

Re: Multi-core processing?

Post by blueyeredragon » April 29th, 2013, 1:38 pm

multi core processing = paralel programming.

https://www.udacity.com/course/cs344

User avatar
Nosferatu
Posts: 36
Joined: July 25th, 2012, 7:08 am
Location: Slovakia

Re: Multi-core processing?

Post by Nosferatu » May 5th, 2013, 7:54 pm

blueyeredragon wrote:multi core processing = paralel programming.

https://www.udacity.com/course/cs344
Dude... what an awesome site :shock: , started learning right away.

Post Reply