Мне нужно было создать statefull расширение ISAPI для моего проекта. Я успешно создал объект TSession, который содержится в классе TSessionList = (TObject). Для очистки прошедших сеансов я создал поток очистки (потомок TThread), который периодически проверяет TSessionList и освобождает все истекшие сеансы.ISAPI Extension TerminateExtension thread deadlock
Я создаю TSessionList и CleanupThread в главном исполнительном блоке dpr. Это нормально. Но на самом деле я не уверен, где положить уничтожение CleanupThread. Из документации я обнаружил, что расширение ISAPI должно экспортировать TerminateExtension, которое вызывается непосредственно перед разгрузкой расширения. По умолчанию Delphi ISAPI-расширение курса экспортирует такую функцию. Поэтому я «переусердствовал» = экспортировал мой TerminateExtension, который освобождает мои объекты сеанса, а затем вызывает по умолчанию ISAPIAPP.TerminateExtensionProc.
Вот это, как он выглядит:
function TerminateExtension(dwFlags: DWORD): BOOL; stdcall;
begin
DoneSessions;
Result:= ISAPIApp.TerminateExtension(dwFlags);
end;
exports
GetExtensionVersion,
HttpExtensionProc,
TerminateExtension;
begin
CoInitFlags := COINIT_MULTITHREADED;
Application.Initialize;
InitSessions;
Application.CreateForm(TSOAPWebModule, SOAPWebModule);
Application.Run;
end.
Разрушение CleanupThread делается DoneSessions так:
begin
CleanupThread.Free;
SessionList.Free;
end;
CleanupThread является простой потомок TThread, поэтому не стоит искать что-нибудь специфический в коде уничтожения.
Проблема заключается в том, что TerminateExtension замерзает только в CleanupThread.Free. Отладка в дальнейшем я обнаружил, что замораживание происходит в TThread.WaitFor. Я подозреваю, что должен быть какой-то тупик потока = рабочий поток ISAPI ждет завершения моего расширения, которое ждет в TThread.WaitFor для основного потока, чтобы получить сигнал (или что-то еще).
Я знаю, что смогу преодолеть эту ситуацию, вызвав CleanupThread.Terminate, а затем используя прямой WaitForSingleObject (или несколько) и, наконец, освободив его. Но это звучит немного ... нестандартно.
Поэтому мой вопрос: как и когда я должен освобождать (завершать - ждать - уничтожать) любые поддерживающие потоки в расширении ISAPI, чтобы избежать тупика?
BTW: Я уже нашел то же самое в стандартной DLL. Если вы поместите какой-либо поток.WaitFor в dll выгрузите proc, ваше основное приложение зависает только в библиотеке. Так что один и тот же вопрос/ответ, надеюсь, применим здесь.