boost:: поток выполнения
У меня есть класс ChunkManager
это имеет несколько (предполагается, что) асинхронных методов. Эти методы обрабатывают задачи в моем игровом движке, такие как загрузка блоков карты (аналогично Minecraft) в другой поток, чтобы не полностью остановить основной поток (это длительные операции). Вот один из этих методов:
void ChunkManager::asyncRenderChunks(){
boost::thread loadingThread(&ChunkManager::renderChunks,this);
}
Где renderChunks выглядит так:
void ChunkManager::renderChunks(){
activeChunksMutex->lock();
for(int z=0; z < CHUNK_MAX; z=z+1)
{
for(int y=0; y < CHUNK_MAX; y=y+1)
{
for(int x=0; x < CHUNK_MAX; x=x+1)
{
activeChunks[x][y][z]->Render(scnMgr);
}
}
}
activeChunksMutex->unlock();
}
Это должно работать, верно? Однако, это терпит крах, когда это бежит. У меня есть ощущение, что это связано с тем, что я делаю с темой после того, как она создана, потому что если я поставлю
loadingThread.join();
в вышеупомянутом методе он работает нормально, но основной поток останавливается, потому что, очевидно, он просто ожидает завершения нового потока, эффективно возвращая меня к исходной точке. Любой совет? Извините, если это запоздалый вопрос, я новичок в концепции потоков. Благодарю.
Обновление (9/9/2013): я нашел этот драгоценный камень: http://threadpool.sourceforge.net/ решил мою проблему!
2 ответа
Если вы можете присоединиться к ветке, она должна быть присоединяемой.
Как сказано в документации:
Когда
boost::thread
объект, представляющий поток выполнения, уничтожается, программа завершается, если поток является присоединяемым.
Вы создали местный thread
объект и сразу же отпустить его из области видимости: он разрушается, когда ChunkManager::asyncRenderChunks
возвращается.
Или:
сделать это отдельным (не присоединяемым) потоком
void ChunkManager::asyncRenderChunks() { boost::thread loadingThread(&ChunkManager::renderChunks,this); loadingThread.detach(); }
или создать
thread
возражать в другом месте и поддерживать егоclass ChunkManager { boost::thread renderingThread; bool renderChunkWork; // work to do flag Chunk activeChunks[CHUNK_MAX][CHUNK_MAX][CHUNK_MAX]; boost::mutex activeChunksMutex; boost::condition_variable activeChunksCV; bool shutdown; // shutdown flag void renderChunks() { for(int z=0; z < CHUNK_MAX; ++z) for(int y=0; y < CHUNK_MAX; ++y) for(int x=0; x < CHUNK_MAX; ++x) activeChunks[x][y][z]->Render(scnMgr); } void renderChunkThread() { boost::unique_lock<boost::mutex> guard(activeChunksMutex); while (true) { while (!(renderChunkWork || shutdown)) activeChunksCV.wait(guard); if (shutdown) break; renderChunks(); doRenderChunks = false; } } public: ChunkManager() : loadingThread(&ChunkManager::renderChunkThread, this), renderChunkWork(false), shutdown(false) {} ~ChunkManager() { { // tell the rendering thread to quit boost::unique_lock<boost::mutex> guard(activeChunksMutex); renderChunkShutdown = true; activeChunksCV.notify_one(); } renderingThread.join() } void asyncRenderChunks() { boost::unique_lock<boost::mutex> guard(activeChunksMutex); if (!renderChunkWork) { renderChunkWork = true; activeChunksCV.notify_one(); } } };
NB. В общем, создание потоков на лету менее полезно, чем предварительное создание потоков и просто пробуждение их, когда есть чем заняться. Это позволяет избежать выяснения, как обрабатывать второй вызов asyncRenderChunks
до завершения последнего (запустить второй поток "блок") и перемещает задержку, связанную с созданием потока.
Обратите внимание на время жизни объекта
Важно понимать, что в этом коде:
void ChunkManager::asyncRenderChunks() {
SomeType myObject;
}
экземпляр myObject
будет создан, а затем сразу же уничтожен.
Вылетает, потому что в текущей версии Boost.Thread
, вы должны либо присоединиться () к потоку или detach()
это - иначе ~thread
завершит программу. (В более ранних версиях ~thread
звонил detach()
автоматически.)
Так что, если вы не хотите присоединяться к потоку - просто отсоедините его:
boost::thread loadingThread(&ChunkManager::renderChunks,this);
loadingThread.detach();