Приложение My Delphi Berlin использует TIdHttpServer
для получения некоторых данных от клиента через HTTP GET, обрабатывает его и отправляет обратно.Ждите выполнения потока внутри обработчика событий OnCommandGet TIdHttpServer
Вся логика выполняется в рамках одного обработчика событий: OnCommandGet
. Идентификатор получен в QueryString, тогда данные будут преобразованы и возвращены обратно клиенту внутри того же обработчика событий OnCommandGet
.
Преобразование данных реализовано в отдельном потоке, который использует PostMessage
, чтобы сообщить основному потоку, что рабочий поток завершает выполнение, и данные готовы к отправке обратно клиенту.
Данные для отправки в AResponseInfo.ContentText
.
Мой вопрос:
Как сделать
OnCommandGet
обработчик ждать пока рабочий поток не делает свою работу и передает указатель на преобразованных данных, поэтому я могу получить значение и стрелять назад вAResponseInfo.ContentText
?
UPDATE Вот псевдо-код, который я хочу, чтобы выполнить:
type
TMyResponsesArray = array[0..5] of TMyObjectAttributes;
PMyResponsesArray = ^TMyResponsesArray;
{There will be 6 tasks run in parallel. Tasks' responses
will be stored in the below declared Responses array.}
var
Responses: TMyResponsesArray;
{Below is a Server handler, which takes the input parameter and calls
a proc which runs 6 threads in parallel. The result of each thread is
stored as an ordered array value. Only when the array is completely
populated, ServerCommandGet may send the response!}
procedure TMainForm.ServerCommandGet(AContext: TIdContext;
ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
var
ObjectId: string;
begin
ObjectId := ARequestInfo.Params.Values['oid'];
RunTasksInParallel(ObjectId);
end;
{Below is a procedure invoked by ServerCommandGet. It runs 6 tasks in
parallel. Each of the thread instantiates an object, sets its basic
parameter and fires the method. Each task runs queued. When each thread
completes the job, it sends a WM to the main thread (via ParentHandler
which must accept and process the response.}
procedure TMainForm.RunTasksInParallel(const ObjectId: string);
const
c: array[0..5] of Byte = (0, 1, 2, 3, 4, 5);
var
ParentHandle: HWND;
begin
{running 6 tasks in parallel}
TTask.Run(
procedure
begin
TParallel.For(Low(c), High(c),
procedure(index: Integer)
var
MyObj: TMyObject;
i: Byte;
begin
i := c[index];
MyObj := TMyObject.Create;
try
MyObj.SetMyParameter := Random(10);
Responses[i] := MyObj.CallMyMethd(ObjectId);
TThread.Queue(nil,
procedure
begin
SendMessage(ParentHandle,
UM_DATAPACKET, i, Integer(@Responses));
end);
finally
MyObj.Free;
end;
end);
end);
end;
{Now the WM handler. It decreases internal task counter and when
TaskCounter = 0, it means that all tasks finished execution and the
Responses array is fully populated. Then we somehow need to pass the
Response array to the ServerCommandGet and send it back to client...}
procedure TMainForm.OnDataPacket(var Msg: TMessage);
begin
i := Msg.WParam;
Responses := PMyResponsesArray(Msg.LParam)^;
{Skipped for for brevity:
When ALL tasks have finished execution, the Responses array is FULL.
Then all array values are wrapped into XML and sent back to initial
invoker ** ServerCommandGet ** which must send XML to client.}
end;
Если 'OnCommandGet' порождает новый поток, вы можете использовать' TThread.WaitFor() '(или даже' WaitForSingleObject() 'непосредственно - только для Windows). Или вы можете просто передать строковый указатель на поток преобразования и связать эту строку с объектом «TEvent», который будет сигнализироваться после заполнения строки, а затем вы можете ждать этого события. –
Просто знайте, что, хотя 'OnCommandGet' заблокирован в ожидании, сервер будет заблокирован от возможности закрыть, если это необходимо, например, при закрытии приложения. Почему вы отправляете данные обратно в * основной поток * вместо потока сервера, который запросил его? В этом отношении, почему трансформация выполняется в отдельном потоке? 'TIdHTTPServer' многопоточен,' OnCommandGet' запускается в своем рабочем потоке для начала. Итак, почему бы просто не преобразовать непосредственно в «OnCommandGet»? –
@RemyLebeau, я обновил вопрос, чтобы вы могли видеть (и критиковать :) логику моего приложения. Это имеет какое-то отношение к 'Parallel.For()' и 'TThread.Queue()'. Я до сих пор не понимаю, как заставить 'ServerCommandGet' ждать, пока не будут обработаны все задачи (в отдельных потоках). –