4

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

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

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 的库。

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

4

1 回答 1

3

根据您最近的评论,这里是一个线程的示例实现,该线程按需唤醒,运行其相应的任务,然后返回睡眠,以及管理它的必要功能(等待任务完成、请求关闭、等待关机)。

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

请注意,一旦您删除了 debug 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!
于 2013-08-22T15:51:14.550 回答