2012-03-26 2 views
0

Мне нужно было создать 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, ваше основное приложение зависает только в библиотеке. Так что один и тот же вопрос/ответ, надеюсь, применим здесь.

ответ

0

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

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

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

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

TerminateThread(CleanupThread.handle,0); 

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

 Смежные вопросы

  • Нет связанных вопросов^_^