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();
Другие вопросы по тегам