Использование boost :: threadpool с boost :: bind приводит к зависанию моей программы в бесконечном цикле - PullRequest
1 голос
/ 04 февраля 2011

Я пытаюсь распараллелить определенный аспект моей программы, используя boost::threadpool (не является официальной частью boost, ссылка ).Тем не менее, я обнаружил, что моя программа зависла, и при проверке htop показывает, что есть два неактивных потока (я подозреваю, в моем пуле потоков) и один поток, работающий на 100% (я подозреваю, что мой основной поток выполнения).

Вот соответствующий код:

namespace rt {

class Renderer
{
  public:
    Renderer(int threads) : tp(threads) {}

    void render(const Scene&, const Camera&, Image&) const;

  private:
    mutable boost::threadpool::pool tp;
    //int tp;

    static void render(const Scene&, const Camera&, Image&, int, int);
    static Color trace_ray(const Ray&, const Scene&, int depth = 0);
};

} // namespace rt
void
Renderer::render(const Scene& scene, const Camera& cam, Image& image) const
{
    for (int y = 0; y < image.get_height(); ++y)
        for (int x = 0; x < image.get_width(); ++x)
            tp.schedule(boost::bind(&Renderer::render, scene, cam, image, x, y));

    tp.wait();
}

void
Renderer::render(const Scene& scene, const Camera& cam, Image& image, int x, int y)
{
    Color c = trace_ray(cam.spawn_ray(x + .25f, y + .25f), scene)
            + trace_ray(cam.spawn_ray(x + .75f, y + .25f), scene)
            + trace_ray(cam.spawn_ray(x + .25f, y + .75f), scene)
            + trace_ray(cam.spawn_ray(x + .75f, y + .75f), scene);

    image.set_pixel(x, y, c / 4.0f);
}

Причина, по которой я подозреваю, что проблема заключается в моей конструкции boost::bind, заключается в том, что когда я создаю функцию void foobar() {} и передаю ее в boost::threadpool::pool::scheduleпрограмма не попадает в бесконечный цикл.Что я тут не так делаю?

Ответы [ 2 ]

1 голос
/ 04 февраля 2011

Аргументы, заданные для boost::bind , будут скопированы .

Аргументы, которые принимает bind: скопированы и хранятся внутри возвращенный объект функции. Например, в следующем коде:

int i = 5;

bind (f, i, _1); копия стоимости я хранится в объекте функции. boost :: ref и boost :: cref могут быть использованы чтобы заставить объект функции хранить ссылка на объект, а не копия.

В вашем случае:

tp.schedule(boost::bind(&Renderer::render, scene, cam, image, x, y));

отправит копии cam, image, x и y на Rendered::render. Это то, что вы намерены?

1 голос
/ 04 февраля 2011

Рассматривали ли вы использование boost :: thread_group в качестве импровизированного пула потоков вместо этого? Что такое реализация wait (), используемая здесь, это имя будет означать барьер, из-за которого ваши потоки могут становиться неактивными бесконечно.

Edit:

Можете ли вы вызывать рендер без перехода в бесконечный цикл? Возможно, это то, как вы отслеживаете или порождаете лучи, которые не показаны. Кроме того, похоже, что вы, возможно, захотите вызвать wait_for_all_tasks в своем пуле потоков на основании краткого взгляда на ссылку, которую вы разместили в его реализации.

...