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

最新のコメントに続いて、オンデマンドでウェイクアップし、対応するタスクを実行してからスリープ状態に戻るスレッドの実装例と、それを管理するために必要な機能 (タスクの完了を待つ、シャットダウンを要求する、待機する) を示します。シャットダウン用)。

関数のセットは固定されているので、あとは必要な数のスレッドを作成するだけです (つまり、おそらく a に 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!
于 2013-08-22T15:51:14.550 に答える