Le code ci-dessous montre une façon de fournir une méthode de serveur avec un comportement de temporisation.
La tâche qui peut prendre trop de temps est exécutée dans un thread secondaire démarré dans la méthode serveur. Cette méthode utilise un objet TSimpleEvent (voir l'aide en ligne) pour permettre au thread secondaire de renvoyer à l'unité d'exécution de la méthode serveur qu'il a terminée. La valeur (en millisecondes) que vous spécifiez dans l'appel à Event.WaitFor
définit le délai d'attente avant l'expiration de l'appel. Si l'appel à WaitFor sur le SimpleEvent expire, vous pouvez prendre n'importe quelle action pour notifier le client du serveur. Si l'appel à WaitFor renvoie wsSignaled, cela signifie que DBThread doit avoir appelé SetEvent sur l'objet Event avant la période spécifiée lors de l'appel WaitFor expiré. Btw, cet exemple a été écrit pour D7, donc pourrait nécessiter une adaptation mineure pour Seattle. En outre, il utilise un descendant TForm comme "serveur", mais devrait fonctionner aussi bien dans une méthode de serveur DataSnap, puisque le principe est le même. Il n'aborde pas la question de savoir exactement comment arrêter la tâche que vous lancez dans le thread secondaire, car si cela est possible et comment le faire si cela dépend de la tâche. À cause de cela, et le fait que vous ne voudriez probablement pas retarder la méthode du serveur en attendant la fin de DBThread, il ne tente pas de libérer le DBThread, bien que dans le monde réel cela devrait bien sûr être fait.
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;
Je pense que vous devez définir "stop". Si, par exemple, votre méthode de serveur prend du temps parce qu'elle attend des données d'un serveur de base de données, voulez-vous simplement signaler au client que la méthode a expiré ou voulez-vous annuler la requête db? – MartynA
Eh bien, je veux juste que le serveur arrête de créer ou d'exécuter tout ce que le serveur fait dans cette méthode. Donc, il finira l'appel et le client peut continuer. – Remi
Dans ce cas, faites le travail fastidieux dans un thread secondaire (je veux dire, secondaire par rapport au thread d'exécution de la méthode) et tuez le thread secondaire si cela prend trop de temps. – MartynA