Game Development Reference
In-Depth Information
Listing 25-1. Creating a
Thread
#include "GameLoop.h"
#include <thread>
void RunGameThread(Game& game)
{
game.RunGame();
}
int _tmain(int argc, _TCHAR* argv[])
{
new SerializationManager();
Game game;
std::thread gameThread{ RunGameThread, std::ref{ game } };
assert(gameThread.joinable());
gameThread.join();
delete SerializationManager::GetSingletonPtr();
return 0;
}
C++ provides the
thread
class that will automatically create a native operating system thread and
execute a function that you pass into its constructor. In this example, we are creating a
thread
named
gameThread
that will run the
RunGameThread
function.
RunGameThread
takes a reference to a
Game
object as a parameter. You can see that we are using
std::ref
to pass the
game
object to
gameThread
. You need to do this because the
thread
class
constructor makes a copy of the object being passed in. Once it has this copy and starts the
thread
, the destructor is called on the copy. Calling
~Game
will call
~Player
, which will unregister
our
m_player
object from the
SerializationManager
. If this happens, our game will crash, as the
m_player
object will not exist whenever the game tries to load the user's save game. The
std::ref
object avoids this by storing a reference to the
game
object internally and making copies of itself.
When the destructors are being called, they are called on the
ref
object and not on the object
passed. This prevents the crash you would otherwise experience.
Execution continues on your original thread once the new
thread
has been created and is running
the function you supplied. At this point you can carry out some other tasks. Text Adventure doesn't
have any other jobs to complete at the moment, and therefore execution would carry on, delete the
SerializationManager
, and
return
. This would cause another crash because your
gameThread
would
go out of scope and try to destroy your running thread. What you really want to happen is for
_tmain
to
stop executing until the task being carried out in
gameThread
has completed. Threads complete when
their function returns and in our case we will be waiting for the player to either quit or win the game.
You make a running thread wait for another by calling
join
on the other thread's object. The
joinable
method is supplied to make sure that the thread you would like to wait on is one that is
valid and running. You can test this by placing a breakpoint on the
delete SerializationManager
line. Your breakpoint will not be hit until you complete your game.