Game Development Reference
In-Depth Information
Listing 25-4. Creating a mutex
std::mutex m_mutex;
std::unique_lock<std::mutex> m_finishedQueryLock{ m_mutex, std::defer_lock };
We have two parts to our mutex , the mutex itself and a wrapper template named unique_lock , which
provides convenient access to the behavior of the mutex . The unique_lock constructor takes a mutex
object as its main parameter. This is the mutex that it acts on. The second parameter is optional;
if it is not supplied, the unique_lock obtains a lock on the mutex immediately but by passing
std::defer_lock we can prevent this from happening.
At this point you might be wondering exactly how a mutex works. A mutex can be locked and
unlocked. We class the process of locking a mutex as obtaining a lock. The unique_lock template
provides three methods to work with the mutex: lock , unlock , and try_lock .
The lock method is a blocking call. This means that your thread's execution will stall until the mutex
has been successfully locked by the thread you called lock from. If the mutex is already locked by
another thread, your thread will wait until the mutex becomes unlocked before proceeding.
The unlock method unlocks a locked mutex . Best practice is to hold your lock for as few lines
of code as possible. Generally this means that you should do any calculations you need before
obtaining a lock, obtain the lock, write the result to the shared variable, and then unlock immediately
to allow other threads to lock the mutex .
The try_lock method is a nonblocking version of lock . This method returns true if the lock was
obtained or false if the lock was not obtained. This allows you to do other work, usually in a loop
within the thread until such time that the try_lock method returns true .
Now that you have seen the code to create a lock, I can show you how to use the unique_lock
template to prevent your Text Adventure game from crashing. Listing 25-5 uses the lock to protect
access to the m_playerQuit and m_playerWon variables in the HasFinished method.
Listing 25-5. Updating Game::HasFinished with the unique_lock
bool HasFinished() const
{
m_finishedQueryLock.lock();
bool hasFinished = m_playerQuit || m_playerWon;
m_finishedQueryLock.unlock();
return hasFinished;
}
The HasFinished method now calls the lock method on m_ finishedQueryLock before it calculates
the value to be stored in the hasFinished variable. The lock is released before the return statement in
the method to allow any waiting threads to be able to lock the mutex .
This is only the first step in being able to protect our program from crashes. The HasFinished
method is called on the main thread but the m_playerWon and m_playerQuit variables are written
to from the game thread . I have added three new methods to protect these variables in the game
thread in Listing 25-6.
 
Search WWH ::




Custom Search