Roland M Smith Ответов: 1

Обработка потоков в расширениях IIS ISAPI


Я написал расширение ISAPI на языке C++, предназначенное для запуска кода PowerBuilder в IIS. С помощью инструментария powerbuilder имеет интерфейс, чтобы позволить C++ код, чтобы позвонить напрямую в код с помощью инструментария powerbuilder.

Одна из функций позволяет ему запустить фоновый поток с помощью CreateThread и вернуться к клиенту до завершения фонового потока.

У одного из пользователей возникает проблема, когда, если два клиентских приложения запрашивают одно и то же примерно в одно и то же время, одно из них прерывается в определенной точке кода PowerBuilder, выполняемого фоновым потоком.

В IIS AppPool-это процесс, а каждый запрос-это поток. Если два потока запросов могут успешно запускать код PowerBuilder одновременно, то почему потоки, созданные потоками запросов, не могут успешно работать?

Что я уже пробовал:

Это код, который запускает фоновый поток:

if (RunBackground) {
       // create the background thread
       hThread = CreateThread(NULL, 0, BackgroundThread, strArgument, 0, &dwThreadID);
       if (hThread != NULL) {
           // wait for background thread to finish setup
           if (strArgument->hEvent != NULL) {
               WaitForSingleObject(strArgument->hEvent, INFINITE);
           }
           // cleanup
           delete strArgument;
           CloseHandle(hThread);
           CloseHandle(strArgument->hEvent);

           // set the HTTP status
           pECB->dwHttpStatusCode = HTTP_STATUS_OK;

           return HSE_STATUS_PENDING;
       }
   }


Функция BackgroundThread инициализирует среду выполнения PowerBuilder и перед вызовом пользовательского кода выполняет следующие действия:

// signal that initialization is done
if (strArgument->hEvent != NULL) {
    SetEvent(strArgument->hEvent);
}

// release the session
pECB->ServerSupportFunction(pECB->ConnID, HSE_REQ_DONE_WITH_SESSION, NULL, NULL, NULL);

1 Ответов

Рейтинг:
1

Joe Woodbury

delete strArgument;
CloseHandle(hThread);
CloseHandle(strArgument->hEvent);
Одна непосредственная проблема заключается в том, что вы используете память после ее освобождения. (Также обратите внимание, что не все пути освобождают эту память. Нужно ли выделять strArgument? Если это так, рассмотрите возможность использования std::unique_ptr или просто создайте экземпляр класса strArgument в стеке и при необходимости очистите его внутренне.)

Я озадачен вторым блоком кода. Есть ли еще код перед выпуском сеанса? Будет ли иметь значение, если первый блок завершится между вызовами SetEvent и ServerSupportFunction?


Roland M Smith

Strargument structure удаляется после оператора 'if' в первом фрагменте кода. Второй фрагмент находится в середине функции BackgroundThread. Все виды использования структуры в фоновом потоке находятся перед вторым фрагментом кода, поэтому я не использую освобожденную память.

Joe Woodbury

удалить strArgument; <==== удалить
CloseHandle(hThread);
CloseHandle(strArgument->hEvent); <=== = use

Joe Woodbury

Кроме того, если hEvent имеет значение NULL, вы можете использовать strArgument в потоке после удаления его в вызывающей функции. (Я видел только сбой CreateEvent в коде стресса, предназначенном для использования всех дескрипторов, и создание потока, скорее всего, потерпело бы неудачу в этом случае, но строго говоря....)

Roland M Smith

Спасибо, что указали на то, что я удалял структуру, прежде чем ссылаться на нее.

Почему я должен удалить "удалить"?

Joe Woodbury

С помощью C++ воспользуйтесь RAII, который помогает предотвратить утечки из-за потери отслеживания точек выхода.

Я лично предпочитаю создать класс, инкапсулирующий поток и передающий право собственности на данные этому классу/потоку. Я бы продублировал дескриптор события (в классе) в вызывающей функции, чтобы мне не нужно было беспокоиться о времени жизни.