'Как видите, это особый пул потоков, так как мне нужно дождаться окончания потоков.' - не полностью. Вы хотите, чтобы поток, который обрабатывает последнюю задачу в вашей работе, предоставлял уведомление о завершении работы. Уведомление о завершении - это обычная функция theadPool, иначе исходящий поток не сможет обработать полный набор результатов. Пулы часто обрабатывают более одной иерархии задач / задач одновременно, поэтому метод уведомления о завершении должен быть независимым от потоков - нет join () или чего-либо подобного. Кроме того, нет WaitForMultipleObject () - используется массив объектов синхронизации, который сложен в управлении и ограничен 64 объектами.
Пулы потоков обычно имеют пул потоков, ожидающих в очереди производителя-потребителя для выполнения задач. Задачи обычно наследуются от некоторого класса 'Ctask', который предоставляет службы пула потоков. Механизм для рассмотрения завершения и уведомления является одним из них.
Очередь «производитель-получатель» - это, по сути, «обычный» класс очередей, защищенный от множественного доступа мьютексом и семафором для подсчета задач в очереди и ожидания потоков. Каждый из потоков пула проходит эту очередь, и они зацикливаются, ожидая семафор очереди, затем извлекают задачи из заблокированной очереди и вызывают метод run () полученных задач.
В каждой задаче пул потоков будет загружен как элемент данных, поскольку он передается в пул. Это позволяет задаче отправлять больше задач, если это необходимо.
Завершение каждой задачи обычно уведомляется где-то, вызывая метод события, являющийся членом задачи, загружаемый исходным потоком до того, как задача отправляется в пул.
Задача также должна иметь целое число обратного отсчета атомной под-задачи и событие для ожидания завершения других задач.
Как это может работать в вашем примере? У вас может быть «основная» задача, которая отправляет задачи обработки массива и ожидает их завершения.
В пуле должно быть больше потоков, чем ядер. Я предлагаю вдвое больше.
Массив необходимо разделить, чтобы для каждого раздела использовалась отдельная задача. Сколько задач - достаточно, чтобы все доступные ядра были израсходованы, но не так много, чтобы генерировались избыточные переключатели контекста. Для любого массива разумного размера предположим, что 64 задачи - это разумное разделение - больше, чем типичное число доступных процессоров. Кроме того, задачи не должны быть разделены последовательно, чтобы избежать ложного обмена.
Итак, это «первичная» задача обработки массива. Загрузите его со ссылкой на массив и установите его событие завершения, чтобы указать на какой-то метод, который сигнализирует о событии. Отправьте задачу в пул, дождитесь события.
Задачи загружаются в поток. Его метод run () использует два цикла и создает 32 задачи обработки массива, каждая со своим собственным начальным индексом и длиной в массиве, но с непоследовательными начальными индексами. Задача использует собственный унаследованный метод submit () для загрузки каждой из 32 новых задач в пул. Помимо фактической постановки в очередь задач для выполнения в потоках, этот метод submit () также атомарно увеличивает целое число счетчиков и устанавливает событие завершения задач в частное событие завершения перед постановкой в очередь задачи. Частное событие завершения атомарно уменьшает счет завершения и сигнализирует событие, если ноль. После отправки всех 32 событий обработки массива основная задача ожидает отдельного события завершения.
Итак, 32 задачи обработки массива выполняются в потоках.По завершении каждого выполняющийся поток вызывает его событие завершения, которое уменьшает целое число счетчиков в основной задаче.В конце концов, последняя задача обработки массива завершается, и целое число счетчиков уменьшается до нуля, что сигнализирует о событии, которого ожидает поток, выполняющий основную задачу.Основная задача вызывает свое собственное событие завершения, поэтому сигнализирует о событии, от которого ожидает основной источник задач.
Основной источник задач запускается с полностью обработанным массивом.
.. или,Вы могли бы использовать класс threadPool, который уже работает, как предложено другими.