2016-11-30 17 views
0

Я создал приложение сервера datasnap для обработки данных между приложением Windows и мобильными приложениями.Остановить метод через определенное время в Delphi Datasnap Server Application

Один способ может занять некоторое время, и я хочу, чтобы он мог остановить его через определенное время (таймаут).

Как я могу это достичь?

+1

Я думаю, вам нужно определить «стоп». Если, скажем, ваш серверный метод занимает некоторое время, потому что он ожидает данных с сервера базы данных, вы просто хотите сообщить клиенту, что этот метод был вычислен, или вы хотите отменить запрос db? – MartynA

+0

Ну, я просто хочу, чтобы сервер прекратил создавать или выполнять все, что делает сервер в этом методе. Таким образом, он завершит вызов, и клиент может продолжить. – Remi

+1

В этом случае выполняйте трудоемкую работу во вторичном потоке (я имею в виду, вторичный по отношению к потоку выполнения метода) и убивают вторичный поток, если он занимает слишком много времени. – MartynA

ответ

2

В приведенном ниже коде представлен один из способов предоставления серверного метода с поведением таймаута.

Задача, которая может занять слишком много времени, выполняется во вторичном потоке, который является , запущенным в методе сервера. Этот метод использует объект 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; 
+0

Ну, это ответ на ваш вопрос или нет? Есть ли что-то, что вы не понимаете в моем ответе? – MartynA