В приведенном ниже коде представлен один из способов предоставления серверного метода с поведением таймаута.
Задача, которая может занять слишком много времени, выполняется во вторичном потоке, который является , запущенным в методе сервера. Этот метод использует объект TSimpleEvent (см. Интерактивную справку), чтобы включить вторичный поток , чтобы передать поток потока метода сервера, который он завершил. Значение (в миллисекундах), которое вы указываете при вызове Event.WaitFor
, определяет, как долго ждать до истечения времени вызова. Если вызов WaitFor на время SimpleEvent, вы можете предпринять любые действия, которые вы делаете , чтобы уведомить клиента сервера. Если вызов WaitFor возвращает wsSignaled, это означает, что DBThread должен был вызвать SetEvent в объекте Event до периода, указанного при вызове WaitFor expired.
Btw, этот пример был написан для D7, поэтому может потребоваться незначительная адаптация для Сиэтл. Также он использует потомок TForm как «сервер», но должен работать одинаково хорошо в методе сервера DataSnap, так как принцип тот же.
В нем не рассматривается вопрос о том, как точно остановить любую задачу, которую вы запускаете во вторичном потоке, потому что, возможно ли это и как это сделать, если это зависит от того, какая именно задача. Из-за этого и того факта, что вы, вероятно, не захотите задерживать метод сервера, ожидая завершения DBThread, он не пытается освободить DBThread, хотя в реальном мире это должно быть сделано.
type
TServer = class;
TDBThread = class(TThread)
private
FServer: TServer;
FEvent: TSimpleEvent;
FCancelled : Boolean;
function GetCancelled: Boolean;
procedure SetCancelled(const Value: Boolean);
public
procedure Execute; override;
constructor Create(AServer : TServer);
property Server : TServer read FServer;
property Event : TSimpleEvent read FEvent;
property Cancelled : Boolean read GetCancelled write SetCancelled;
end;
TServer = class(TForm)
// ignore the fact that in this case, TServer is a descendant of TForm
Button1: TButton;
procedure Button1Click(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
protected
CS : TCriticalSection;
Event : TSimpleEvent;
public
procedure DoServerMethod;
end;
[...]
{ TDBThread }
constructor TDBThread.Create(AServer: TServer);
begin
inherited Create(True); // create suspended
FreeOnTerminate := False;
FServer := AServer;
FEvent := FServer.Event;
end;
procedure TDBThread.Execute;
var
StartTime : Cardinal;
begin
Cancelled := False;
// Following is for illustration ONLY, to simulate a process which takes time.
// Do not call Sleep() in a loop in a real thread
StartTime := GetTickCount;
repeat
Sleep(100);
until GetTickCount - StartTime > 5000;
if not Cancelled then begin
{ TODO : Transfer result back to server thread }
Event.SetEvent;
end;
end;
function TDBThread.GetCancelled: Boolean;
begin
FServer.CS.Enter;
try
Result := FCancelled;
finally
FServer.CS.Leave;
end;
end;
procedure TDBThread.SetCancelled(const Value: Boolean);
begin
FServer.CS.Enter;
try
FCancelled := Value;
finally
FServer.CS.Leave;
end;
end;
procedure TServer.DoServerMethod;
var
DBThread : TDBThread;
WaitResult : TWaitResult;
begin
DBThread := TDBThread.Create(Self);
DBThread.Resume;
WaitResult := Event.WaitFor(1000);
case WaitResult of
wrSignaled : begin
// the DBThread completed
ShowMessage('DBThread completed');
end;
wrTimeOut : begin
// the DBThread time out
DBThread.Cancelled := True;
ShowMessage('DBThread timed out');
// Maybe use PostThreadMessage here to tell the DBThread to abort (if possible)
// whatever task it is doing that has taken too long.
end;
end; {case}
{ TODO : Terminate and dispose of the DBThread }
end;
procedure TServer.FormCreate(Sender: TObject);
begin
CS := TCriticalSection.Create;
Event := TSimpleEvent.Create;
end;
procedure TServer.Button1Click(Sender: TObject);
begin
DoServerMethod;
end;
Я думаю, вам нужно определить «стоп». Если, скажем, ваш серверный метод занимает некоторое время, потому что он ожидает данных с сервера базы данных, вы просто хотите сообщить клиенту, что этот метод был вычислен, или вы хотите отменить запрос db? – MartynA
Ну, я просто хочу, чтобы сервер прекратил создавать или выполнять все, что делает сервер в этом методе. Таким образом, он завершит вызов, и клиент может продолжить. – Remi
В этом случае выполняйте трудоемкую работу во вторичном потоке (я имею в виду, вторичный по отношению к потоку выполнения метода) и убивают вторичный поток, если он занимает слишком много времени. – MartynA