Актуальные вопросы :
О C ++ 11:
- С ++ 11: пул std :: thread?
- Будет ли async (launch :: async) в C ++ 11 делать пулы потоков устаревшими, чтобы избежать создания дорогостоящих потоков?
О Boost:
Как получить пул потоков для отправки задач , не создавая и не удаляя их снова и снова? Это означает, что постоянные потоки будут повторно синхронизироваться без присоединения.
У меня есть код, который выглядит так:
namespace {
std::vector<std::thread> workers;
int total = 4;
int arr[4] = {0};
void each_thread_does(int i) {
arr[i] += 2;
}
}
int main(int argc, char *argv[]) {
for (int i = 0; i < 8; ++i) { // for 8 iterations,
for (int j = 0; j < 4; ++j) {
workers.push_back(std::thread(each_thread_does, j));
}
for (std::thread &t: workers) {
if (t.joinable()) {
t.join();
}
}
arr[4] = std::min_element(arr, arr+4);
}
return 0;
}
Вместо того, чтобы создавать и объединять потоки на каждой итерации, я бы предпочел отправлять задачи своим рабочим потокам на каждой итерации и создавать их только один раз.
Ответы:
Вы можете использовать библиотеку пула потоков C ++, https://github.com/vit-vit/ctpl .
Затем код, который вы написали, можно заменить следующим
Вы получите желаемое количество потоков и не будете создавать и удалять их снова и снова на итерациях.
источник
results[j] = p.push([&arr, j](int){ arr[j] +=2; });
Это скопировано из моего ответа на другой очень похожий пост, надеюсь, это поможет:
1) Начните с максимального количества потоков, которое может поддерживать система:
2) Для эффективной реализации пула потоков после создания потоков в соответствии с Num_Threads лучше не создавать новые и не уничтожать старые (путем присоединения). Это приведет к снижению производительности, может даже сделать ваше приложение медленнее, чем последовательная версия.
Каждый поток C ++ 11 должен выполняться в своей функции с бесконечным циклом, постоянно ожидая захвата и запуска новых задач.
Вот как прикрепить такую функцию к пулу потоков:
3) Функция Infinite_loop_function
Это цикл while (true), ожидающий очереди задач
4) Сделайте функцию для добавления работы в вашу очередь
5) Привяжите произвольную функцию к вашей очереди
После интеграции этих компонентов у вас будет собственный динамический пул потоков. Эти потоки всегда выполняются, ожидая выполнения задания.
Прошу прощения, если есть какие-то синтаксические ошибки, я набрал этот код и у меня плохая память. Извините, что я не могу предоставить вам полный код пула потоков, это нарушит мою честность работы.
Изменить: чтобы завершить работу пула, вызовите метод shutdown ():
источник
std::vector
не требует, чтобы его элементы были копируемыми. Вы можете использовать векторы с ходу только типов (unique_ptr
,thread
,future
и т.д.).condition.wait
также искать переменнуюstop_
и проверятьif (stop_ == true) { break;}
?Пул потоков означает, что все ваши потоки работают постоянно - другими словами, функция потока никогда не возвращается. Чтобы дать потокам что-то значимое, вы должны разработать систему межпотокового взаимодействия, как с целью сообщить потоку, что нужно что-то сделать, так и для передачи фактических рабочих данных.
Обычно это будет связано с какой-то параллельной структурой данных, и каждый поток предположительно будет спать на какой-то переменной условия, которая будет уведомлена, когда есть работа. После получения уведомления один или несколько потоков просыпаются, восстанавливают задачу из параллельной структуры данных, обрабатывают ее и аналогичным образом сохраняют результат.
Затем поток продолжит проверять, нужно ли еще поработать, и если не вернется в режим сна.
В результате вам придется спроектировать все это самостоятельно, поскольку не существует универсального универсального понятия «работа». Это довольно большая работа, и есть некоторые тонкие проблемы, которые вам нужно решить. (Вы можете программировать на Go, если вам нравится система, которая негласно позаботится об управлении потоками.)
источник
Пул потоков - это, по сути, набор потоков, связанных с функцией, работающей как цикл событий. Эти потоки будут бесконечно ждать выполнения задачи или своего собственного завершения.
Задача пула потоков заключается в предоставлении интерфейса для отправки заданий, определения (и, возможно, изменения) политики выполнения этих заданий (правила планирования, создание экземпляров потоков, размер пула) и мониторинг состояния потоков и связанных ресурсов.
Итак, для универсального пула нужно начать с определения, что такое задача, как она запускается, прерывается, каков результат (см. Понятие обещания и будущего для этого вопроса), на какие события потоки должны будут реагировать. как они будут их обрабатывать, как эти события должны отличаться от тех, которые обрабатываются задачами. Как видите, это может стать довольно сложным и накладывать ограничения на работу потоков, поскольку решение становится все более сложным.
Текущие инструменты для обработки событий довольно просты (*): примитивы, такие как мьютексы, условные переменные, и несколько абстракций в дополнение к этому (блокировки, барьеры). Но в некоторых случаях эти абстракции могут оказаться непригодными (см. Связанный с этим вопрос ), и нужно вернуться к использованию примитивов.
Также необходимо решить другие проблемы:
Как это отразится в вашем окружении?
Этот ответ на аналогичный вопрос указывает на существующую реализацию, предназначенную для boost и stl.
Я предложил очень грубую реализацию пула потоков для другого вопроса, который не решает многие проблемы, описанные выше. Возможно, вы захотите развить это. Вы также можете взглянуть на существующие фреймворки на других языках, чтобы найти вдохновение.
(*) Я не вижу в этом проблемы, скорее, наоборот. Я думаю, что это сам дух C ++, унаследованный от C.
источник
источник
Что-то вроде этого может помочь (взято из рабочего приложения).
Вы можете использовать это так:
Имейте в виду, что изобретение эффективного механизма асинхронной организации очередей - нетривиальная задача.
Boost :: asio :: io_service - очень эффективная реализация или фактически представляет собой набор специфичных для платформы оболочек (например, он обертывает порты завершения ввода-вывода в Windows).
источник
std::thread
хватит?std
дляboost::thread_group
.boost::thread_group
представляет собой наборboost::thread
экземпляров. Но, конечно, очень просто заменитьboost::thread_group
на avector
ofstd::thread
s.Изменить: теперь для этого требуется C ++ 17 и концепции. (По состоянию на 9/12/16 достаточно только g ++ 6.0+.)
Тем не менее, вывод шаблонов из-за этого намного точнее, поэтому стоит потратить усилия на получение более нового компилятора. Я еще не нашел функцию, которая требует явных аргументов шаблона.
Теперь он также принимает любой подходящий вызываемый объект ( и все еще статически типизирован !!! ).
Он также теперь включает дополнительный пул потоков с приоритетом зеленого потока, использующий тот же API. Однако этот класс - только POSIX. Он использует
ucontext_t
API для переключения задач в пользовательском пространстве.Я создал для этого простую библиотеку. Пример использования приведен ниже. (Я отвечаю на это, потому что это была одна из вещей, которые я нашел до того, как решил, что необходимо написать это сам.)
Вы можете передать
async
любую функцию с любым (или недействительным) возвращаемым значением и любыми (или без) аргументами, и она вернет соответствующийstd::future
. Чтобы получить результат (или просто дождаться выполнения задачи), вы обращаетесьget()
к будущему.Вот гитхаб: https://github.com/Tyler-Hardin/thread_pool .
источник
Это еще одна реализация пула потоков, которая очень проста, легка в понимании и использовании, использует только стандартную библиотеку C ++ 11 и может быть просмотрена или изменена для ваших целей, должна быть хорошим стартером, если вы хотите начать использовать поток бассейны:
https://github.com/progschj/ThreadPool
источник
Вы можете использовать thread_pool из библиотеки boost:
Вы также можете использовать threadpool из сообщества с открытым исходным кодом:
источник
Пул потоков без зависимостей вне STL вполне возможен. Недавно я написал небольшую библиотеку пула потоков только для заголовков, чтобы решить ту же проблему. Он поддерживает динамическое изменение размера пула (изменение количества рабочих во время выполнения), ожидание, остановку, приостановку, возобновление и так далее. Надеюсь, вы сочтете это полезным.
источник