Прежде всего, я все еще знакомлюсь с многопоточными и не знаю много терминов. Мне нужно убедиться, что я делаю это правильно, потому что это чувствительная тема.Управление динамическим числом потоков
Технические характеристики
Что я строю это компонент, который будет содержать динамический число потоков. Каждый из этих потоков повторно используется для выполнения нескольких запросов. Я могу предоставить все необходимые детали для потока, когда я его создаю, и перед тем, как выполнить его, а также предоставить обработчики событий. Как только он будет выполнен, я в значительной степени выполнил один запрос, и я подаю другой запрос. Запросы подаются в эти потоки из другого автономного фонового потока, который постоянно обрабатывает очередь запросов. Таким образом, эта система имеет два списка: 1) Список записей запроса и 2) Список указателей потоков.
Я использую потомки класса TThread
(по крайней мере, это метод потоков, с которым я знаком). Я получаю обратную связь от потоков, синхронизируя триггеры событий, которые я назначил при создании потоков. Потоки загружают и сохраняют данные в фоновом режиме, и когда они завершатся, они перезагружаются, чтобы обработать следующий запрос.
Проблема
Теперь проблема начинается при принятии решения о том, как обрабатывать событие изменения числа разрешенных потоков (через свойство компонента ActiveThreads: TActiveThreadRange
который TActiveThreadRange
= 1..20). Следовательно, между 1 и 20 потоками, создаваемыми за один раз, может быть где угодно. Но когда, скажем, приложение, использующее этот компонент, изменит это свойство с 5 на 3. В это время уже создано 5 потоков, и я не хочу принудительно освобождать этот поток, если он оказывается занятым. Мне нужно подождать, пока это не будет сделано, прежде чем я освобожу его. А с другой стороны, если свойство изменено с 3 на 5, мне нужно создать 2 новых потока. Мне нужно знать правильный подход к «отслеживанию» этих потоков в этом сценарии.
Возможности
Вот некоторые из возможных способов, которыми я могу думать о том, чтобы «следе» эти нити ...
- Ведите
TList
, содержащий каждую созданную нить - легко управлять - Создать a
TList
обертка или потомок, содержащий каждый созданный поток - проще в управлении, но больше работы - Держите
array
contai ning каждый созданный поток - будет ли это лучше, чемTList
? - Создать обертку массива, содержащей каждую созданной нить
Но затем вернуться к моему первоначальному вопросу - Что делать с существующими занятыми нитями, когда свойство ActiveThreads
уменьшается? Создание их не проблема, но освобождение их становится запутанным. Я обычно делаю потоки, которые освобождают себя, но это первый раз, когда я создал тот, который повторно используется. Мне просто нужно знать правильный метод уничтожения этих потоков, не прерывая их задач.
Update
На основе обратной связи, я приобрел и начал реализацию OmniThreadLibrary (а также долго необходимой FastMM). Я также изменил свой подход немного - способ, что я могу создать эти резьбовые процессы без управления ими и без другого потока для обработки очереди ...
- 1 мастер-метод, чтобы породить новый процесс
function NewProcess(const Request: TProcessRequest): TProcessInfo;
TProcessRequest
представляет собой запись с характеристиками того, что должно быть сделано (имя файла, параметры и т.д.)TProcessInfo
является запись, которая передает обратно информацию о состоянии.
- Подача обработчика события для случая «выполнения» с его задачей при создании нового процесса. Когда компонент получает это сообщение, он проверяет очередь.
- Если команда находится в очереди, он будет сравнивать активный предельный процесс с текущим процессом подсчитывать
- > Если превышает предел, только остановится и следующий завершен процесс будет делать выполнить одну проверку
- > Если в пределе, пинают от другого новый процесс (после обеспечения предыдущего процесса делается)
- Если ни одна из команд не выстраиваются в очередь, а затем просто остановить
- Каждый процесс может умереть в одиночку после того, как он выполнил свою задачу (без поддержания активности потоковая)
- не придется беспокоиться о другом таймер или поток постоянно через петлю
- Вместо того, чтобы каждый процесс разрушает его личность и проверяет наличие новых запросов, прежде чем делать так
Очередное обновление
Я действительно вернусь к использованию TThread
, так как OTL очень неудобно использовать. Мне нравится держать вещи обернутыми и организованными в своем классе.
То, о чем вы просите, известно как «пул потоков»; возможно, это поможет вам найти ресурсы. –
См. [Delphi-threaded-list-of-thread-jobs-queueing] (http://stackoverflow.com/questions/1805633/delphi-threaded-list-of-thread-jobs-queueing). И не сверните свой собственный пул потоков, посмотрите на [OTL-OmniThreadLibrary] (http://code.google.com/p/omnithreadlibrary/). –
Мой личный опыт заключается в том, что проще работать с API Windows напрямую, чем полагаться на 'TThread', если вы выполняете более сложную работу. На самом деле, очень легко начать потоки с использованием Windows API. Начните с простых экспериментов с ['CreateThread'] (http://msdn.microsoft.com/en-us/library/windows/desktop/ms682453 (v = vs.85) .aspx). Просто остерегайтесь, что вы, как разработчик Delphi, вероятно, должны использовать оболочку 'System.BeginThread' вместо' CreateThread', но, конечно же, документация MSDN «CreateThread» остается в силе. –