Вопрос, поднятый в данном запросе, касается использования новой библиотеки потоков в Delphi для выполнения задач параллельно с использованием метода TTask.WaitForAny() для получения первого результата. Однако, при использовании этого метода иногда возникает исключение EMonitorLockException с сообщением "Object lock not owned". В контексте вопроса уже содержится решение проблемы, а именно - обнаруженный баг в библиотеке потоков, связанный с использованием TMonitor и/или TTask.WaitForAny(). Пользователь пытался сократить код до минимума для воспроизведения ошибки, что подтверждает наличие бага. В качестве альтернативного ответа предложено использование TParallel.For для остановки выполнения при получении ответа, с использованием сигналов состояния параллельного цикла.
Подтвержденный ответ:
Использование TParallel.For позволяет остановить выполнение всех задач, как только одна из них выполнит условие остановки. В примере кода, представленном в альтернативном ответе, используется критическая секция для защиты переменных, которые могут быть изменены в параллельных потоках. Как только условие остановки выполнено, сигнал loopState.Stop останавливает все текущие и ожидающие итерации.
Пример кода на Object Pascal (Delphi):
procedure Parallel3(CS: TCriticalSection);
var
Ticks: Cardinal;
i, ix: Integer;
begin
i := 0;
Ticks := TThread.GetTickCount;
TParallel.For(1, WorkerCount,
procedure(index: Integer; loopState: TParallel.TLoopState)
var
k, l, m: Integer;
begin
// Сложные вычисления
k := (1000 - index) * 1000;
for l := 0 to Pred(k) do
m := k div 1000;
// Если условие остановки выполнено:
CS.Enter;
try
if loopState.Stopped then // Результат уже найден
Exit;
loopState.Stop; // Сигнал остановки
Inc(i);
ix := index;
finally
CS.Leave;
end;
end);
Ticks := TThread.GetTickCount - Ticks;
WriteLn('Parallel time ' + Ticks.ToString + ' ticks', ' i :', i, ' index:', ix);
end;
Обратите внимание, что в критической секции CS защищаются переменные i и ix. После выполнения условия остановки, все итерации параллельного цикла должны быть остановлены, и текущие итерации проверяют состояние loopState.Stopped.
Альтернативное решение с использованием OTL:
Автор альтернативного ответа выразил опасения относительно текущего состояния библиотеки System.Threading, рекомендуя использовать альтернативный фреймворк OTL. Для остановки выполнения задач в OTL можно использовать cancelToken.Signal для установки сигнала остановки и cancelToken.IsSignaled для проверки состояния.
Заключение:
При работе с параллельными вычислениями важно тщательно планировать взаимодействие потоков и использовать механизмы синхронизации, чтобы избежать конфликтов доступа и исключений, связанных с блокировками. В случае обнаружения багов в библиотеках, рекомендуется переходить на более стабильные и проверенные решения, такие как OTL.
Пользователь столкнулся с исключением `EMonitorLockException` при использовании библиотеки потоков в Delphi для параллельных вычислений и нашел решение проблемы в виде бага, связанного с использованием `TMonitor` и `TTask.WaitForAny
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.