我使用略有不同的方法来阻塞线程,我不知道这是否会以任何方式或不帮助,但我不介意分享我所提供的不同意见或办法。
BlockThread.h
#ifndef BLOCK_THREAD_H
#define BLOCK_THREAD_H
namespace vmk {
class BlockThread sealed {
private:
CRITICAL_SECTION* m_pCriticalSection;
public:
explicit BlockThread(CRITICAL_SECTION& criticalSection);
~BlockThread();
private:
BlockThread(const BlockThread& c); // Not Implemented
BlockThread& operator=(const BlockThread& c); // Not Implemented
// void swap(BlockThread& other) throw();
}; // BlockThread
} // namespace vmk
#endif // BLOCK_THREAD_H
BlockThread.cpp
#include "stdafx.h"
#include "BlockThread.h"
namespace vmk {
// ----------------------------------------------------------------------------
// BlockThread()
BlockThread::BlockThread(CRITICAL_SECTION& criticalSection) {
m_pCriticalSection = &criticalSection;
EnterCriticalSection(m_pCriticalSection);
} // BlockThread
// ----------------------------------------------------------------------------
// ~BlockThread()
BlockThread::~BlockThread() {
LeaveCriticalSection(m_pCriticalSection);
} // ~BlockThread
} // namespace vmk
VolatileLocker.h
#ifndef VOLATILE_LOCKER_H
#define VOLATILE_LOCKER_H
namespace vmk {
template <typename T>
class VolatileLocker {
private:
T* m_pObject;
CRITICAL_SECTION* m_pCriticalSection;
public:
VolatileLocker(volatile T& objectToLock, CRITICAL_SECTION& criticalSection);
~VolatileLocker();
T* operator->();
private:
VolatileLocker(const VolatileLocker& c); // Not Implemented
VolatileLocker& operator=(const VolatileLocker& c); // Not Implemented
}; // VolatileLocker
#include "VolatileLocker.inl"
} // namespace vmk
#endif // VOLATILE_LOCKER_H
// reference: http://drdobbs.com/cpp/184403766
VolatileLocker。INL
// ----------------------------------------------------------------------------
// VolatileLocker()
// Locks A Volatile Variable So That It Can Be Used Across Multiple Threads Safely
template<typename T>
VolatileLocker<T>::VolatileLocker(volatile T& objectToLock, CRITICAL_SECTION& criticalSection) :
m_pObject(const_cast<T*>(&objectToLock)),
m_pCriticalSection(&criticalSection) {
EnterCriticalSection(m_pCriticalSection);
} // VolatileLocker
// ----------------------------------------------------------------------------
// ~VolatileLocker()
template<typename T>
VolatileLocker<T>::~VolatileLocker() {
LeaveCriticalSection(m_pCriticalSection);
} // ~VolatileLocker
// ----------------------------------------------------------------------------
// operator->()
// Allow The Locked Object To Be Used Like A Pointer
template <typename T>
T* VolatileLocker<T>::operator->() {
return m_pObject;
} // operator->
下面是一个使用BlockThread类对象 - 这个类取决于这里没有显示其他类和我将只包括本类使用BlockThread对象的部分。
AudioManager.cpp
#include "stdafx.h"
#include "AudioManager.h"
#include "AudioBuffer.h"
#include "AudioSource.h"
#include "BlockThread.h"
#include "Logger.h"
namespace vmk {
static AudioManager* s_pAudioManager = nullptr;
static CRITICAL_SECTION s_csChangeSources;
// ----------------------------------------------------------------------------
// AudioManager()
AudioManager::AudioManager() :
Singleton(Singleton::TYPE_AUDIO_MANAGER) {
InitializeCriticalSection(&s_csChangeSources);
if (!alutInit(NULL, NULL)) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " ALUT error: " << alutGetErrorString(alutGetError());
throw ExceptionHandler(strStream);
}
alGetError(); // Clear Errors
alListenerf(AL_GAIN, 1.0f); // Master Volume
alListener3f(AL_POSITION, 0.0f, 0.0f, 0.0f);
alListener3f(AL_VELOCITY, 0.0f, 0.0f, 0.0f);
float f6Orient[] = { 0.0f, 0.0f, -1.0f, // Forward(X, Y, Z)
0.0f, 1.0f, 0.0f }; // Up(X,Y,Z)
alListenerfv(AL_ORIENTATION, f6Orient);
if (alGetError() != AL_NO_ERROR) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " Failed to initialize Listener";
throw ExceptionHandler(strStream);
}
s_pAudioManager = this;
} // AudioManager
// ----------------------------------------------------------------------------
// ~AudioManager()
AudioManager::~AudioManager() {
s_pAudioManager = nullptr;
m_mAudioSources.clear();
m_lAudioBuffers.clear();
alutExit();
DeleteCriticalSection(&s_csChangeSources);
} // ~AudioManager
// ----------------------------------------------------------------------------
// get()
AudioManager* const AudioManager::get() {
if (nullptr == s_pAudioManager) {
throw ExceptionHandler(__FUNCTION__ + std::string(" failed, AudioManager has not been constructed yet"));
}
return s_pAudioManager;
} // get
// ----------------------------------------------------------------------------
// Create A Sound Source Using The Passed In Filename. If The File Is Not
// Already Loaded Into A Memory Buffer, Then A New Buffer Is Created.
void AudioManager::createSource(SoundSource eSoundSource, const std::string& strFilename, bool bAttachToListener) {
BlockThread blockThread(s_csChangeSources);
if (!isAvailable(eSoundSource)) {
return;
}
std::shared_ptr<AudioBuffer> pAudioBuffer = nullptr;
// Check If This File Has Already Been Loaded Into A Buffer
for (ListAudioBuffers::iterator itBuffer = m_lAudioBuffers.begin(); itBuffer != m_lAudioBuffers.end(); ++itBuffer) {
if ((*itBuffer)->isThisFile(strFilename)) {
// The Requested File Is Already Loaded Into Memory
pAudioBuffer = (*itBuffer);
break;
}
}
try {
if (nullptr == pAudioBuffer) {
// Need To Load The Desired File Into Memory
pAudioBuffer.reset(new AudioBuffer(strFilename));
// Store The Buffer
m_lAudioBuffers.push_back(pAudioBuffer);
}
// Create New Source Attached To The Desired Audio Buffer
m_mAudioSources[eSoundSource] = std::shared_ptr<AudioSource>(new AudioSource(eSoundSource, pAudioBuffer, bAttachToListener));
} catch (...) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " failed for SoundSource(" << eSoundSource << ")";
Logger::log(strStream, Logger::TYPE_ERROR);
}
} // createSource
// ----------------------------------------------------------------------------
// Removes Source From Map And If Buffer Is No Longer Needed,
// It Will Also Be Deleted
void AudioManager::deleteSource(SoundSource eSoundSource) {
BlockThread blockThread(s_csChangeSources);
MapAudioSources::iterator it = m_mAudioSources.find(eSoundSource);
if (it == m_mAudioSources.end()) {
std::ostringstream strStream;
strStream << __FUNCTION__ << " could not find SoundSource(" << eSoundSource << ")";
Logger::log(strStream, Logger::TYPE_ERROR);
return; // Nothing To Delete
}
// Get bufferId And Delete Source
unsigned uBufferId = it->second->getBufferId();
m_mAudioSources.erase(it);
// Find Buffer In List
if (uBufferId != INVALID_UNSIGNED) {
for (ListAudioBuffers::iterator itBuffer = m_lAudioBuffers.begin(); itBuffer != m_lAudioBuffers.end(); ++itBuffer) {
if ((*itBuffer)->getId() == uBufferId) {
if ((*itBuffer)->getNumberSourcesAttached() < 1) {
// Buffer No Longer Needed
m_lAudioBuffers.erase(itBuffer);
return;
} // If Buffer Not Needed
} // If Found Buffer
} // For All Buffers
} // If Buffer Is Loaded
} // deleteSource
// ----------------------------------------------------------------------------
// getAudioObject()
AudioObject* AudioManager::getAudioObject(SoundSource eSoundSource) const {
BlockThread blockThread(s_csChangeSources);
MapAudioSources::const_iterator it = m_mAudioSources.find(eSoundSource);
if (it != m_mAudioSources.cend()) {
return it->second.get();
}
std::ostringstream strStream;
strStream << __FUNCTION__ << " SoundSource(" << eSoundSource << ") has not been found";
Logger::log(strStream, Logger::TYPE_ERROR);
return nullptr;
} // getAudioObject
} // namespace vmk
以及使用VolatileLocker的将是如下:注:我这儿也有未示出的OpenglThread类对象,允许对OpenGL的多线程工作。
Game.cpp
#include "Game.h"
#include "OpenglThread.h"
#include "VolatileLocker.h"
... other class object includes
namespace vmk {
static CRITICAL_SECTION s_criticalSection;
// ----------------------------------------------------------------------------
// Game()
Game::Game() :
Engine(glm::uvec2(3, 3)),
m_maxSpeechArea(250, INVALID_UNSIGNED),
m_eLastSpeechSound(SS_INTRO_SHOT),
m_eSoundSourceToPlay(SS_INTRO_SHOT) {
InitializeCriticalSection(&s_criticalSection);
const glm::uvec2 gamePixelSize = m_pSettings->getGameSize();
// (0,0) In Top Left Corner Not Bottom Left Which Is The Default
m_m4Projection = glm::ortho(0.0f, static_cast<float>(gamePixelSize.x), static_cast<float>(gamePixelSize.y), 0.0f, -10.0f, 10.0f);
// Set Background Color
glClearColor(22.0f/255.0f, 22.0f/255.0f, 22.0f/255.0f, 1.0f);
// Turn Transparencies On
glEnable(GL_BLEND);
// Initialize Shaders
std::string strVertexShader("Shaders/gui.vert");
std::string strFragmentShader("Shaders/gui.frag");
ShaderProgramSettings shaderProgramSettings(P_MAIN, strVertexShader, strFragmentShader);
shaderProgramSettings.addVariable(ShaderAttribute(A_POSITION, AT_FLOAT_VEC2), "inPosition");
shaderProgramSettings.addVariable(ShaderAttribute(A_COLOR, AT_FLOAT_VEC4), "inColor");
shaderProgramSettings.addVariable(ShaderAttribute(A_TEXTURE_COORD0, AT_FLOAT_VEC2), "inTextureCoord0");
shaderProgramSettings.addVariable(ShaderUniform(U_MVP_MATRIX, UT_FLOAT_MAT4), "modelViewProjectionMatrix");
shaderProgramSettings.addVariable(ShaderUniform(U_TEXTURE0_SAMPLER_2D, UT_SAMPLER_2D), "texture0Sampler2d");
shaderProgramSettings.addVariable(ShaderUniform(U_USING_TEXTURE, UT_BOOL), "usingTexture");
shaderProgramSettings.addVariable(ShaderUniform(U_ALPHA, UT_FLOAT), "inAlpha");
m_pShaderManager->create(shaderProgramSettings);
m_pShaderManager->enable(P_MAIN);
m_pBatchManager.reset(new BatchManager(10, 10000));
// Must Be Called Before Any GuiElements Are Loaded
GuiElement::initialize();
// Load Game Logo - Title Screen
m_pTitleScreen = new GuiScreen(std::string("TitleScreen"));
TextureFileReader titleTextureFileReader("Assets/images/titleScreen.png");
m_titleTextureInfo = titleTextureFileReader.getOrCreateTextureInfo(TextureInfo::FILTER_NONE, false, false);
// Start Worker Thread
_beginthread(loadAssets, 0, this);
// Game Logo
GuiLayoutAbsolute* pTitleCoverLayout = new GuiLayoutAbsolute(glm::ivec2(), Gui::LEFT, m_pSettings->getGameSize(), "title cover");
pTitleCoverLayout->setColor(glm::vec4(0.0862745, 0.0862745, 0.0862745, 1.0));
m_pTitleScreen->addChild(pTitleCoverLayout);
m_pTitleLayout = new GuiLayoutAbsolute(glm::ivec2(0, 200), Gui::LEFT, glm::uvec2(955, 400), "title");
m_pTitleLayout->setBackgroundImage(m_titleTextureInfo, glm::uvec2(0, 359), glm::uvec2(955, 400));
m_pTitleLayout->changePriority(1);
m_pTitleScreen->addChild(m_pTitleLayout);
// Flying Bullet
m_pFlyingBulletLayout = new GuiLayoutAbsolute(glm::ivec2(40, -100), "flying bullet");
m_pTitleLayout->addChild(m_pFlyingBulletLayout);
// Intro Sound Effect
m_pAudioManager->createSource(SS_INTRO_SHOT, "Assets/audio/introShot.ogg");
m_pAudioManager->play(SS_INTRO_SHOT);
// Set Timer For How Long Title Screen Should Be Visible
m_pAnimationManager->addFunction(5.0, Animation::LINEAR, splashScreenUpdate, this, splashScreenDone, this);
/*
int debugLogging = m_pSettings->getDebugLogging() | Settings::DEBUG_RENDER;
m_pSettings->setDebugLogging(debugLogging);
*/
} // Game
// ----------------------------------------------------------------------------
// ~Game()
Game::~Game() {
DeleteCriticalSection(&s_criticalSection);
} // ~Game
// ----------------------------------------------------------------------------
// splashScreenDone()
// Defined Outside Of Game But Is Declared As A Friend Function To Game And It Utilizes The VolatileLocker
void splashScreenDone(void* pParameter) {
Game* pGame = reinterpret_cast<Game*>(pParameter);
if (nullptr == pGame) {
throw ExceptionHandler(__FUNCTION__ + std::string(" Invalid pParameter passed in"));
}
VolatileLocker<GameState>(pGame->m_gameState, s_criticalSection)->timerDone();
if (VolatileLocker<GameState>(pGame->m_gameState, s_criticalSection)->is(GameState::PLAYING)) {
pGame->m_pAudioManager->play(SS_CHOOSE_LETTER);
}
} // splashScreenDone
// ----------------------------------------------------------------------------
// keyboardInput()
// A Member Function Of Game That Utilizes The VolatileLocker
void Game::keyboardInput(unsigned vkCode, bool isPressed) {
if (isPressed || VolatileLocker<GameState>(m_gameState, s_criticalSection)->isSplashScreen()) {
// Wait For Splash Screen To Be Finished
// Only React To Key Release Events
return;
}
static unsigned lastKey = 0;
if ((VK_ESCAPE == lastKey && VK_ESCAPE == vkCode) ||
(VK_ESCAPE == vkCode && m_bGameOver)) {
// TODO: Show Credits
quitGame(nullptr, nullptr);
return;
}
lastKey = vkCode;
if (m_bGameOver) {
if (VK_SPACE == vkCode) {
restart();
}
return;
}
if (VK_ESCAPE == vkCode) {
updateSpeech("To qui the game, press ESC again.", COLOR_YELLOW);
speak(SS_QUIT_GAME);
} else if (vkCode >= VK_KEYA && vkCode <= VK_KEYZ) {
// Play Sound
m_pAudioManager->play(SS_GUN_SHOT);
updatePuzzle(static_cast<char>(vkCode));
// Show Gun Fire & Start Timer To Reset Graphics Back To Normal
showGunFire(true);
m_pAnimationManager->addTimer(0.2, resetGunGraphics, this);
} else {
updateSpeech("Choose a letter.");
speak(SS_CHOOSE_LETTER);
}
} // keyboardInput
} // namespace vmk
现在我知道在一个线程池或队列工作中提到的OP,但我认为是能够锁定主题为安全起见整体概念可以在这里显示以及。这也可以作为任何人阅读的指南。
听起来像是程序员的一个很好的问题.SE,FWIW。 –
@PreferenceBean我认为这是一个很好和有效的问题(不过SE程序员也没有这样的经验)。 –
@πάνταῥεῖ:它没有代码,我希望看到我们向程序员发送更多优质内容,所以我们不会饿死它。但我不反对。 –