Часть задачи в группе задач выполняется в главном потоке вместо выделенного потока - PullRequest
0 голосов
/ 08 июня 2019

У меня проблема с tbb parallel_for() и task_group::run(). У меня есть код, который запускает задачу в потоке, используя task_group::run(). В этой задаче я использую parallel_for() для распараллеливания функции.

С другой стороны, в главном потоке я выполняю другие вычисления, и в какой-то момент я также вызываю parallel_for() для других вещей. Проблема, с которой я столкнулся, состоит в том, что tbb повторно использует «основной поток» этого второго материала для вызова кода запуска до group (без вызова wait() на group).

В моем случае это создает проблему, я не хочу, чтобы первое задание вызывало какой-либо вызов в основном потоке. Причиной является проблема пользовательского интерфейса, у меня есть код, который проверяет, находимся мы в главном потоке или нет, чтобы обновить некоторые элементы пользовательского интерфейса. И обновление пользовательского интерфейса во время второго parallel_for() приведет к проблеме в этом конкретном случае.

Вот код, который представляет проблему:

using namespace std::chrono_literals;

tbb::task_group group;

auto mainThreadId = std::this_thread::get_id();
std::atomic<bool> needWait(true);
std::atomic<bool> taskOnThreadFinish(false);
group.run(
    [&]
    {
        eastl::vector<int> values(20, 0);
        tbb::parallel_for_each(
            values.begin(),
            values.end(),
            [&](int i)
            {
                while(needWait)
                    std::this_thread::sleep_for(1ms);

                // Should never, ever, never be call on the main thread, but it could be the case in TBB !!!!!!
                assert(mainThreadId != std::this_thread::get_id());

                std::this_thread::sleep_for(1ms);
            });

        taskOnThreadFinish = true;
    });

eastl::vector<int> mainThreadValues(10, 0);
tbb::parallel_for_each(
    mainThreadValues.begin(),
    mainThreadValues.end(),
    [&](int i)
    {
        needWait = false;
        std::this_thread::sleep_for(1ms);
    });

while(!taskOnThreadFinish)
    std::this_thread::sleep_for(1ms);

Так что мой вопрос: как избежать повторного использования основного потока, когда второй вызов tbb :: parallel_for_each () сделан?

Обратите внимание, что код, использующий новую параллельную функцию / поведение std, работает хорошо.

UPDATE

Использование tbb :: task_arena решает проблему, потому что она изолирует task_group внутри арены.

tbb::task_group arena;
tbb::task_group group;

...
arena.execute(
    [&]
    {
        group.Run(
            [&]
            {
                ...
            });
    });
...