ISAPI расширение TerminateExtension поток тупик - PullRequest
0 голосов
/ 27 марта 2012

Мне нужно было создать расширение ISAPI для моего проекта.Я успешно создал объект TSession, который содержится в классе TSessionList = (TObject).Для очистки сеансов с истекшим сроком действия я создал поток очистки (потомок TThread), который периодически сканирует TSessionList и освобождает все сеансы с истекшим сроком действия.

Я создаю 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 (или Multiple ???) и, наконец, освободить его.Но это звучит немного ... нестандартно.

Поэтому мой вопрос таков: как и когда я должен освободить (Terminate - WaitFor - Destroy) любые потоки поддержки в расширении ISAPI, чтобы избежать тупиковых потоков?

Кстати: я уже нашел то же самое в стандартной DLL.Если вы поместите какой-нибудь поток.WaitFor в процесс выгрузки dll, ваше основное приложение зависнет только при выгрузке библиотеки.Так что тот же самый вопрос / ответ, надеюсь, применим и здесь.

1 Ответ

0 голосов
/ 27 марта 2012

Вы должны попытаться сигнализировать о завершении потока перед вызовом free, например;

CleanupThread.Terminate;
if CleanupThread.Waitfor(60000)<>WR_Abandoned then //wait for 60sec for cleanup
  CleanupThread.free
else
  //do something sensible on timeout or error

Но, не зная, что именно пытается сделать поток очистки, трудно сказать, что может вызвать тупик. Часто это результат условий гонки, особенно если истекает время ожидания завершения и ожидания, поэтому вам необходимо указать, что делает поток.

В качестве хака (и не очень хорошей практики для многопоточности) вы можете принудительно завершить поток, используя вызов winapi TERMINATETHREAD (в модуле Windows);

TerminateThread(CleanupThread.handle,0);

Поскольку это вызывает немедленный выход из потока, но также означает, что очистка потока не выполняется - помните, что вызов TTHREAD.TERMINATE не гарантирует выхода из потока - это полностью зависит от кода вашего потока, если что-то блокирует ваш нить потом не закончится обычным образом. TerminateThread может решить эту проблему за счет того, что код просто останавливается там, где он не имеет никакого отношения к освобождению ресурсов или каким-либо другим потокам.

...