Интересный момент: мы не позволяем потребителям ждать
go_consume.wait_for
добавляем дополнительный аргумент timeout
, имеющий значение, равное 1
секунде. Он представляет собой механизм выхода для потребителей: если очередь пуста более секунды, то, возможно, активных производителей больше не осталось.Для простоты код пытается поддерживать длину очереди
Рассмотрим следующую ситуацию, которую позволяет элегантно решить condition_variable:
go_produce
, то, возможно, множество производителей пытаются перегнать друг друга в попытке создать новый элемент. При нехватке только одного элемента работать будет только один производитель. Если все производители всегда станут создавать элемент при появлении события go_produce
, то мы зачастую будем сталкиваться с ситуацией, когда очередь заполняется сверх своего максимального размера.Представим ситуацию, когда у нас в очереди имеется (max-1)
Независимо от того, какой метод вызовет поток-потребитель — go_produce.notify_ one()
go_produce.notify_all()
(возобновит go_produce.wait
, поскольку для остальных потоков-производителей не будет удовлетворяться условие ожидания q.size() в момент получения ими мьютекса при пробуждении.
Распараллеливание отрисовщика множества Мандельброта в ASCII с применением std::async
Помните
Далее мы применим минимальные модификации к программе и увидим, что вся программа работает быстрее. После применения этих модификаций программа будет работать с std::async
std::future
. Чтобы полностью уяснить данный пример, очень важно понять оригинальную программу.Как это делается
В этом примере мы возьмем отрисовщик фрактала Мандельброта, который реализовали в главе 6. Сначала увеличим время вычисления, повысив границу вычислений. Затем ускорим программу, внеся четыре небольших изменения, чтобы распараллелить ее.
1. Чтобы следовать шагам, лучше всего скопировать всю программу из другого примера. Затем следуйте инструкциям, показанным в следующих шагах, для внесения всех необходимых изменений. Все отличия от оригинальной программы выделяются
Первое изменение — это дополнительный заголовочный файл
#include
#include
#include
#include
#include
#include
#include
using namespace std;
2. Функции scaler
scaled_cmplx
менять не нужно:using cmplx = complex
static auto scaler(int min_from, int max_from,
double min_to, double max_to)
{
const int w_from {max_from - min_from};
const double w_to {max_to - min_to};
const int mid_from {(max_from - min_from) / 2 + min_from};
const double mid_to {(max_to - min_to) / 2.0 + min_to};
return [=] (int from) {
return double(from - mid_from) / w_from * w_to + mid_to;
};
}
template
static auto scaled_cmplx(A scaler_x, B scaler_y)
{
return [=](int x, int y) {
return cmplx{scaler_x(x), scaler_y(y)};
};
}
3. В функции mandelbrot_iterations
static auto mandelbrot_iterations(cmplx c)
{
cmplx z {};