Потребление элементов в очереди с блокировкой обработки в некоторых случаях

У меня есть один поток, который толкает в очередь и тот, который потребляет элементы из очереди. Обработка одного из элементов асинхронна, но я не хочу обрабатывать другие элементы во время обработки. (Предположим, что выходной поток и очередь потокобезопасны)

Интересно, что лучший способ реализовать поток потребления ... Я думаю, что пока (правда) и условия не лучший выбор.

Простая реализация (process2 должна быть синхронной).

#include <iostream>
#include <queue>
#include <thread>
#include <atomic>
#include <future>

std::atomic_bool isProcess2Processing{false};

void process0()
{
    std::cout << "process0" << std::endl;
}

void process1()
{
    std::cout << "process1" << std::endl;
}

void process2()
{
    std::async(std::launch::async, []() { isProcess2Processing = true; std::cout << "start process2" << std::endl; while (std::rand() > 10000) {}; std::cout << "finished proces2" << std::endl; isProcess2Processing = false; });
}

void consume(int x)
{
    if (x == 0)
    {
        process0();
    }
    else if (x == 1)
    {
        process1();
    }
    else
    {
        process2();
    }
}

int main()
{
    std::queue<int> q;

    std::thread consumingThread([&q]() {
        while (true) {
            if (!q.empty() && !isProcess2Processing) {
                consume(q.front());
                q.pop();
            }
        }
    });

    while (true)
    {
        q.push(std::rand() % 3);
    }
}
0
задан 13 August 2018 в 15:30

1 ответ

Интересно, какой лучший способ реализовать потребительский поток ... Я думаю, что пока (правда) и условия не лучший выбор.

Ваше созерцание здесь оправдано: самая большая проблема с использованием такого цикла while (т. е. без какого-либо ожидания) заключается в том, что вы теряете время и мощность процессора. Ваш вторичный поток (и для кода, предоставленного вашему основному потоку) также сохраняет ядро ​​процессора в течение некоторого времени без видимых причин, так что другие задачи не могут получить процессорное время для себя.

Самый наивный путь к изменению, который добавляет какой-то sleep, как здесь:

std::thread consumingThread([&q]() {
    while (true) {
        if (!q.empty() && !isProcess2Processing) {
            consume(q.front());
            q.pop();
        }
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
});

Здесь вы будете спать в течение 5 мс, в течение которого планировщик сможет позволить другим задачам выполнять свою работу.

Несколько вещей, кроме того, вы должны убедиться, что для каждого цикла есть условие выхода, а также вызывать consumingThread.join();, прежде чем покинуть main().

0
ответ дан 15 August 2018 в 17:00

Другие вопросы по тегам:

Похожие вопросы: