首页 > 解决方案 > std::thread 不会让我的 CPU 负载超过 20%?

问题描述

也许我使用 std::thread 错误?我有一个 12 线程 cpu 并构建了一个渲染引擎。更像是一个绘图仪,用于诸如 perlin 噪声等之类的东西……由于渲染速度很慢,我使用 std::thread 来充分利用我的 12 个内核。渲染速度实际上显着提高,但我的 cpu 使用率不会比仅使用一个线程时高......

这是我负责渲染的代码……让我试着解释一下……

void Renderer::Render(sf::Image * _img,
                      sf::Vector2f _dims,
                      unsigned _threadCount)
{
    im = _img;
    dims = _dims;

    im->create(dims.x, dims.y, sf::Color(100, 0, 0, 255));

    static float bar = 0.3f;
    float g = 0.01f;

    std::vector < std::thread > workers;

    for (unsigned i = 0; i < _threadCount; ++i)
    {
        workers.push_back(std::thread(Renderer::RenderThread,
                                      sf::IntRect((dims.x / _threadCount) * i,
                                                  0,
                                                  (dims.x / _threadCount) * (i + 1),
                                                  dims.y),
                                      bar,
                                      g,
                                      sf::Color(0,
                                                (255.0f / _threadCount) * i,
                                                0)));
    }

    bar += 0.01f;

    for (unsigned i = 0; i < workers.size(); ++i)
    {
        workers[i].join();
    }

    return;
}

void Renderer::RenderThread(sf::IntRect area, float bar, float g, sf::Color clr)
{
    for (unsigned x = area.left + 1; x < area.width + 1; x++)
    {
        for (unsigned y = area.top + 1; y < area.height + 1; y++)
        {
            im->setPixel(x - 1, y - 1, ImAlg::Tiles0(x, y, bar, 5));
        }
    }

    return;
}

所以基本上它的作用如下: 上层函数是主函数,由框架调用。它创建线程。较低的函数是在每个线程上运行的函数。我试图将要渲染的图像分成均匀的部分。就像图像是 1000 宽并且我会使用 4 个线程一样,每个线程都会渲染 250x1000 像素

标签: c++windowsmultithreadingrenderingsfml

解决方案


不要使用原始线程。从一个简单的线程池开始:

struct thread_pool {
  std::future<void> run( std::function<void()> f ){
    std::packaged_task<void()> t(std::move(f));
    auto r = t.get_future();
    auto l = lock();
    q.push_back(std::move(t));
    cv.notify_one();
    return r;
  }
  void start(std::size_t n){
    //std::cout << n << " threads starting" << std::endl;
    while(n--)
      threads.push_back( std::thread([this]{loop();}) );
   }
  ~thread_pool(){
    end();
    for (auto&&t:threads)t.join();
  }
private:
  void end(){
    auto n=threads.size();
    auto l=lock();
    for(auto count=n;count;--count)
      q.emplace_back();
    cv.notify_all();
    //std::cout << n << " threads ended" << std::endl;
  }
  void loop(){
    while(true){
      //std::cout << "Waiting..." << std::endl;
      auto t=pop();
      //std::cout << "Got " << t.valid() << std::endl;
      if (!t.valid()) break;
      //std::cout << "Running..." << std::endl;
      t();
    }
  }
  std::packaged_task<void()> pop(){
    auto l=lock();
    cv.wait(l, [&]{ return !q.empty();});
    auto r = std::move(q.front());
    q.pop_front();
    return r;
  }
  std::vector<std::thread> threads;

  std::unique_lock<std::mutex> lock(){ return std::unique_lock<std::mutex>(m); }
  std::mutex m;
  std::deque<std::packaged_task<void()>> q;
  std::condition_variable cv;
};

活生生的例子

使用线程池;传入需要线程的代码,并预先启动线程(可能基于硬件并发)。 run任务。等待从 run 方法返回的未来。

这将比按需旋转线程快得多。


推荐阅读