游戏循环中的线程管理?

时间:2013-08-21 22:48:47

标签: multithreading c++11 directx-11

我正在开发一款游戏并遇到了多线程的问题。我在加载资源时已经成功使用了多线程。我通过在某个时刻创建一些线程,为它们分配函数,并等待它们完成,同时绘制加载屏幕,这非常简单。

现在我想创建一些线程,它们可以等待空闲直到它们收到一个函数,当它们执行时,解决它,然后再次保持空闲状态。它们必须在游戏循环中运行,这大致是这样的(我想出了这些函数名称只是为了方便可视化):

std::thread t0,t1;
while(gamerunning)
{
   UpdateGame();
   t0.receiveFunc( RenderShadow );
   t1.receiveFunc( RenderScene );
   WaitForThreadstoFinishWork();
   RenderEverything(); //Only draw everything if the threads finished (D3D11's Deferred Context rendering)
}
t0.Destroy();
t1.Destroy();

我的渲染引擎正在运行,并且暂时(用于测试),我在游戏循环中创建了线程,这是一种甚至是快速测试的可怕方式,因为我的渲染速度甚至变慢了。顺便说一下,我正在使用C ++ 11的库。

长话短说,我想在我的游戏循环发生之前创建线程,然后在游戏循环中使用它们,希望有人可以帮助我。如果它是一个选项,我真的希望远离较低级别的线程,我只需要最简单的方法来做到这一点。

1 个答案:

答案 0 :(得分:3)

根据您最近的评论,这是一个按需唤醒的线程的示例实现,运行其相应的任务然后重新进入休眠状态,以及管理它的必要功能(等待任务完成,请求关机,等待关机。)

由于你的函数集是固定的,你所要做的只是创建你需要的线程(即7,可能在vector中),每个都有自己相应的任务。

请注意,一旦删除调试cout,就会留下很少的代码,所以我认为不需要解释代码(这是非常不言自明的恕我直言)。但是,如果您需要解释一些细节,请不要犹豫。

class TaskThread {
public:
    TaskThread(std::function<void ()> task)
      : m_task(std::move(task)),
        m_wakeup(false),
        m_stop(false),
        m_thread(&TaskThread::taskFunc, this)
    {}
    ~TaskThread() { stop(); join(); }

    // wake up the thread and execute the task
    void wakeup() {
        auto lock = std::unique_lock<std::mutex>(m_wakemutex);
        std::cout << "main: sending wakeup signal..." << std::endl;
        m_wakeup = true;
        m_wakecond.notify_one();
    }
    // wait for the task to complete
    void wait() {
        auto lock = std::unique_lock<std::mutex>(m_waitmutex);
        std::cout << "main: waiting for task completion..." << std::endl;
        while (m_wakeup)
          m_waitcond.wait(lock);
        std::cout << "main: task completed!" << std::endl;
    }

    // ask the thread to stop
    void stop() {
        auto lock = std::unique_lock<std::mutex>(m_wakemutex);
        std::cout << "main: sending stop signal..." << std::endl;
        m_stop = true;
        m_wakecond.notify_one();
    }
    // wait for the thread to actually be stopped
    void join() {
        std::cout << "main: waiting for join..." << std::endl;
        m_thread.join();
        std::cout << "main: joined!" << std::endl;
    }

private:
    std::function<void ()> m_task;

    // wake up the thread
    std::atomic<bool> m_wakeup;
    bool m_stop;
    std::mutex m_wakemutex;
    std::condition_variable m_wakecond;

    // wait for the thread to finish its task
    std::mutex m_waitmutex;
    std::condition_variable m_waitcond;

    std::thread m_thread;

    void taskFunc() {
        while (true) {
            {
                auto lock = std::unique_lock<std::mutex>(m_wakemutex);
                std::cout << "thread: waiting for wakeup or stop signal..." << std::endl;
                while (!m_wakeup && !m_stop)
                    m_wakecond.wait(lock);
                if (m_stop) {
                    std::cout << "thread: got stop signal!" << std::endl;
                    return;
                }
                std::cout << "thread: got wakeup signal!" << std::endl;
            }

            std::cout << "thread: running the task..." << std::endl;
            // you should probably do something cleaner than catch (...)
            // just ensure that no exception propagates from m_task() to taskFunc()
            try { m_task(); } catch (...) {}
            std::cout << "thread: task completed!" << std::endl;

            std::cout << "thread: sending task completed signal..." << std::endl;
            // m_wakeup is atomic so there is no concurrency issue with wait()
            m_wakeup = false;
            m_waitcond.notify_all();
        }
    }
};

int main()
{
    // example thread, you should really make a pool (eg. vector<TaskThread>)
    TaskThread thread([]() { std::cout << "task: running!" << std::endl; });

    for (int i = 0; i < 2; ++i) { // dummy example loop
      thread.wakeup();
      // wake up other threads in your thread pool
      thread.wait();
      // wait for other threads in your thread pool
    }
}

这是我得到的(实际订单因运行而异,具体取决于线程安排):

main: sending wakeup signal...
main: waiting for task completion...
thread: waiting for wakeup or stop signal...
thread: got wakeup signal!
thread: running the task...
task: running!
thread: task completed!
thread: sending task completed signal...
thread: waiting for wakeup or stop signal...
main: task completed!
main: sending wakeup signal...
main: waiting for task completion...
thread: got wakeup signal!
thread: running the task...
task: running!
thread: task completed!
thread: sending task completed signal...
thread: waiting for wakeup or stop signal...
main: task completed!
main: sending stop signal...
main: waiting for join...
thread: got stop signal!
main: joined!