C++ - отображать индикатор выполнения при использовании std::async

Поэтому я работаю над трассировщиком лучей, и чтобы сократить время рендеринга, я использовал std::async для независимого вычисления пикселей. Я использовал этот учебник, и все отлично работает, и действительно, мне удалось сэкономить около 70% времени рендеринга.

Тем не менее, некоторые сцены требуют времени для рендеринга, и я хотел бы отобразить какой-то индикатор выполнения. Поскольку я довольно новичок в Async Infra, я не совсем уверен, как это сделать. Мне бы хотелось, чтобы какой-то механизм выводил информацию о прогрессе только из потока main, call.

Здесь цикл рендеринга - обратите внимание на закомментированные строки для индикатора выполнения - который, очевидно, не должен идти туда:

Image *image = new Image(width, height);

size_t max = width * height;
size_t cores = std::thread::hardware_concurrency();
volatile atomic<size_t> count(0);
vector<future<void>> future_vector;

while (cores--)
{
    future_vector.push_back(
        std::async(launch::async, [=, &camera, &scene, &count]()
        {
            while (true)
            {
                std::size_t index = count++;
                if (index >= max)
                    break;

                GLuint i = index % width;
                GLuint j = index / width;

                Ray ray = camera.generateRay(i + .5, j - .5);
                vec3 color = recursiveRayTrace(scene, ray, maxDepth);
                image->setPixel(i, j, color);

                // THIS IS BAD
                //std::cout << "Progress: [ "<< setprecision(1) << fixed << (count / (GLfloat)max) * 100.0 << "% ] \r";
                //std::cout.flush();

            }
        }));
}

for (auto& e : future_vector) {
    e.get();
}

return image;

ОБНОВЛЕНИЕ: Таким образом, я сделал то, что предложили некоторые ответы - вот результаты - для будущих читателей. Мой тест для нескольких сцен составлял 15 секунд (я сделал что-то быстрое специально) при асинхронном рендеринге. Когда я использовал мьютекс, время замедлялось до 26 секунд. (Все еще лучше, чем 1.32 на однопоточном). Я также активно ждал одного из рабочих потоков и продолжал обновлять прогресс каждые 100 миль или около того - и время рендеринга составляло 16 секунд. Поэтому я очень доволен этим результатом, так как печать едва замедлила процесс.

Спасибо алон

1 ответ

Решение

Кажется, вам нужен замок при использовании std::cout иначе асинхронные задачи будут выводить беспорядок (все они будут пытаться одновременно печатать на консоли). Однако я рекомендую вам использовать GDIplus (кажется, вы используете в своем коде) для печати текста, а не показывать в окне консоли, что довольно уродливо.

Image *image = new Image(width, height);

size_t max = width * height;
size_t cores = std::thread::hardware_concurrency();
volatile atomic<size_t> count(0);
vector<future<void>> future_vector;
mutex cout_lock;
while (cores--)
{
    future_vector.push_back(
        std::async(launch::async, [=, &camera, &scene, &count]()
        {
            while (true)
            {
                std::size_t index = count++;
                if (index >= max)
                    break;

                GLuint i = index % width;
                GLuint j = index / width;

                Ray ray = camera.generateRay(i + .5, j - .5);
                vec3 color = recursiveRayTrace(scene, ray, maxDepth);
                image->setPixel(i, j, color);

                {  //lock variable scope
                   lock_guard<mutex> lock(cout_lock)
                   std::cout << "Progress: [ "<< setprecision(1) << fixed << (count / (GLfloat)max) * 100.0 << "% ] \r";
                   std::cout.flush();
                }

            }
        }));
}

for (auto& e : future_vector) {
    e.get();
}

return image;
Другие вопросы по тегам