* Allow server to run message queue in a thread

git-svn-id: trunk@33705 -
This commit is contained in:
michael 2016-05-17 20:09:23 +00:00
parent 253589b0b6
commit 365a246c9a
6 changed files with 222 additions and 24 deletions

View File

@ -40,6 +40,7 @@
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/> <IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../units/$(TargetCPU)-$(TargetOS)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
</CompilerOptions> </CompilerOptions>

View File

@ -6,6 +6,7 @@ uses sysutils,simpleipc;
Var Var
I,Count : Integer; I,Count : Integer;
DoStop : Boolean;
begin begin
Count:=1; Count:=1;
@ -13,11 +14,19 @@ begin
try try
ServerID:='ipcserver'; ServerID:='ipcserver';
If (ParamCount>0) then If (ParamCount>0) then
ServerInstance:=Paramstr(1); begin
if ParamCount>1 then DoStop:=(ParamStr(1)='-s') or (paramstr(1)='--stop');
Count:=StrToIntDef(ParamStr(2),1); if DoStop then
ServerInstance:=Paramstr(2)
else
ServerInstance:=Paramstr(1);
if (Not DoStop) and (ParamCount>1) then
Count:=StrToIntDef(ParamStr(2),1);
end;
Active:=True; Active:=True;
for I:=1 to Count do if DoStop then
SendStringMessage('stop')
else for I:=1 to Count do
SendStringMessage(Format('Testmessage %d from client',[i])); SendStringMessage(Format('Testmessage %d from client',[i]));
Active:=False; Active:=False;
finally finally

View File

@ -6,7 +6,6 @@
<Flags> <Flags>
<MainUnitHasCreateFormStatements Value="False"/> <MainUnitHasCreateFormStatements Value="False"/>
<MainUnitHasTitleStatement Value="False"/> <MainUnitHasTitleStatement Value="False"/>
<UseDefaultCompilerOptions Value="True"/>
</Flags> </Flags>
<SessionStorage Value="InProjectDir"/> <SessionStorage Value="InProjectDir"/>
<MainUnit Value="0"/> <MainUnit Value="0"/>
@ -29,6 +28,7 @@
<RunParams> <RunParams>
<local> <local>
<FormatVersion Value="1"/> <FormatVersion Value="1"/>
<CommandLineParams Value="-t"/>
</local> </local>
</RunParams> </RunParams>
<Units Count="1"> <Units Count="1">
@ -44,6 +44,8 @@
<Filename Value="ipcserver"/> <Filename Value="ipcserver"/>
</Target> </Target>
<SearchPaths> <SearchPaths>
<IncludeFiles Value="$(ProjOutDir)"/>
<OtherUnitFiles Value="../units/$(TargetCPU)-$(TargetOS)"/>
<UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/> <UnitOutputDirectory Value="lib/$(TargetCPU)-$(TargetOS)"/>
</SearchPaths> </SearchPaths>
</CompilerOptions> </CompilerOptions>

View File

@ -5,31 +5,79 @@ program ipcserver;
{$APPTYPE CONSOLE} {$APPTYPE CONSOLE}
uses uses
{$ifdef unix}cthreads,{$endif}
SysUtils, SysUtils,
Classes,
simpleipc; simpleipc;
Type
TApp = Class(TObject)
Srv : TSimpleIPCServer;
DoStop : Boolean;
Procedure MessageQueued(Sender : TObject);
procedure Run;
Procedure PrintMessage;
end;
Procedure TApp.PrintMessage;
Var Var
Srv : TSimpleIPCServer;
S : String; S : String;
begin
S:=Srv.StringMessage;
Writeln('Received message : ',S);
DoStop:=DoStop or (S='stop');
end;
Procedure TApp.MessageQueued(Sender : TObject);
begin
Srv.ReadMessage;
PrintMessage;
end;
Procedure TApp.Run;
Var
S : String;
Threaded : Boolean;
begin begin
Srv:=TSimpleIPCServer.Create(Nil); Srv:=TSimpleIPCServer.Create(Nil);
Try Try
S:= ParamStr(1);
Threaded:=(S='-t') or (S='--threaded');
Srv.ServerID:='ipcserver'; Srv.ServerID:='ipcserver';
Srv.Global:=True; Srv.Global:=True;
Srv.StartServer; if Threaded then
Writeln('Server started. Listening for messages'); Srv.OnMessageQueued:=@MessageQueued;
Srv.StartServer(Threaded);
Writeln('Server started. Listening for messages. Send "stop" message to stop server.');
Repeat Repeat
If Srv.PeekMessage(1,True) then If Threaded then
begin begin
S:=Srv.StringMessage; Sleep(10);
Writeln('Received message : ',S); CheckSynchronize;
end end
else if Srv.PeekMessage(10,True) then
PrintMessage
else else
Sleep(10); Sleep(10);
Until CompareText(S,'stop')=0; Until DoStop;
Finally Finally
Srv.Free; Srv.Free;
end; end;
end;
begin
With TApp.Create do
try
Run
finally
Free;
end;
end. end.

View File

@ -24,7 +24,8 @@ uses
Const Const
MsgVersion = 1; MsgVersion = 1;
DefaultThreadTimeOut = 50;
//Message types //Message types
mtUnknown = 0; mtUnknown = 0;
mtString = 1; mtString = 1;
@ -33,7 +34,6 @@ type
TIPCMessageOverflowAction = (ipcmoaNone, ipcmoaDiscardOld, ipcmoaDiscardNew, ipcmoaError); TIPCMessageOverflowAction = (ipcmoaNone, ipcmoaDiscardOld, ipcmoaDiscardNew, ipcmoaError);
var var
// Currently implemented only for Windows platform!
DefaultIPCMessageOverflowAction: TIPCMessageOverflowAction = ipcmoaNone; DefaultIPCMessageOverflowAction: TIPCMessageOverflowAction = ipcmoaNone;
DefaultIPCMessageQueueLimit: Integer = 0; DefaultIPCMessageQueueLimit: Integer = 0;
@ -125,32 +125,46 @@ Type
{ TSimpleIPCServer } { TSimpleIPCServer }
TMessageQueueEvent = Procedure(Sender : TObject; Msg : TIPCServerMsg) of object;
TSimpleIPCServer = Class(TSimpleIPC) TSimpleIPCServer = Class(TSimpleIPC)
protected protected
Private Private
FOnMessageError: TMessageQueueEvent;
FOnMessageQueued: TNotifyEvent;
FQueue : TIPCServerMsgQueue; FQueue : TIPCServerMsgQueue;
FGlobal: Boolean; FGlobal: Boolean;
FOnMessage: TNotifyEvent; FOnMessage: TNotifyEvent;
FMsgType: TMessageType; FMsgType: TMessageType;
FMsgData : TStream; FMsgData : TStream;
FThreadTimeOut: Integer;
FThread : TThread;
FLock : TRTLCriticalSection;
FErrMsg : TIPCServerMsg;
procedure DoMessageQueued;
procedure DoMessageError;
function GetInstanceID: String; function GetInstanceID: String;
function GetMaxAction: TIPCMessageOverflowAction; function GetMaxAction: TIPCMessageOverflowAction;
function GetMaxQueue: Integer;
function GetStringMessage: String; function GetStringMessage: String;
procedure SetGlobal(const AValue: Boolean); procedure SetGlobal(const AValue: Boolean);
procedure SetMaxAction(AValue: TIPCMessageOverflowAction); procedure SetMaxAction(AValue: TIPCMessageOverflowAction);
procedure SetMaxQueue(AValue: Integer);
Protected Protected
FIPCComm: TIPCServerComm; FIPCComm: TIPCServerComm;
procedure StartThread; virtual;
procedure StopThread; virtual;
Function CommClass : TIPCServerCommClass; virtual; Function CommClass : TIPCServerCommClass; virtual;
Procedure PushMessage(Msg : TIPCServerMsg); virtual; Procedure PushMessage(Msg : TIPCServerMsg); virtual;
function PopMessage: Boolean; virtual; function PopMessage: Boolean; virtual;
Procedure Activate; override; Procedure Activate; override;
Procedure Deactivate; override; Procedure Deactivate; override;
Property Queue : TIPCServerMsgQueue Read FQueue; Property Queue : TIPCServerMsgQueue Read FQueue;
Property Thread : TThread Read FThread;
Public Public
Constructor Create(AOwner : TComponent); override; Constructor Create(AOwner : TComponent); override;
Destructor Destroy; override; Destructor Destroy; override;
Procedure StartServer; Procedure StartServer(Threaded : Boolean = False);
Procedure StopServer; Procedure StopServer;
Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean; Function PeekMessage(TimeOut : Integer; DoReadMessage : Boolean): Boolean;
Procedure ReadMessage; Procedure ReadMessage;
@ -160,8 +174,17 @@ Type
Property MsgData : TStream Read FMsgData; Property MsgData : TStream Read FMsgData;
Property InstanceID : String Read GetInstanceID; Property InstanceID : String Read GetInstanceID;
Published Published
Property ThreadTimeOut : Integer Read FThreadTimeOut Write FThreadTimeOut;
Property Global : Boolean Read FGlobal Write SetGlobal; Property Global : Boolean Read FGlobal Write SetGlobal;
// Called during ReadMessage
Property OnMessage : TNotifyEvent Read FOnMessage Write FOnMessage; Property OnMessage : TNotifyEvent Read FOnMessage Write FOnMessage;
// Called when a message is pushed on the queue.
Property OnMessageQueued : TNotifyEvent Read FOnMessageQueued Write FOnMessageQueued;
// Called when the queue overflows and MaxAction = ipcmoaError.
Property OnMessageError : TMessageQueueEvent Read FOnMessageError Write FOnMessageError;
// Maximum number of messages to keep in the queue
property MaxQueue: Integer read GetMaxQueue write SetMaxQueue;
// What to do when the queue overflows
property MaxAction: TIPCMessageOverflowAction read GetMaxAction write SetMaxAction; property MaxAction: TIPCMessageOverflowAction read GetMaxAction write SetMaxAction;
end; end;
@ -464,12 +487,13 @@ begin
FBusy:=False; FBusy:=False;
FMsgData:=TStringStream.Create(''); FMsgData:=TStringStream.Create('');
FQueue:=TIPCServerMsgQueue.Create; FQueue:=TIPCServerMsgQueue.Create;
FThreadTimeOut:=DefaultThreadTimeOut;
end; end;
destructor TSimpleIPCServer.Destroy; destructor TSimpleIPCServer.Destroy;
begin begin
FreeAndNil(FQueue);
Active:=False; Active:=False;
FreeAndNil(FQueue);
FreeAndNil(FMsgData); FreeAndNil(FMsgData);
inherited Destroy; inherited Destroy;
end; end;
@ -488,6 +512,11 @@ begin
FQueue.MaxAction:=AValue; FQueue.MaxAction:=AValue;
end; end;
procedure TSimpleIPCServer.SetMaxQueue(AValue: Integer);
begin
FQueue.MaxCount:=AValue;
end;
function TSimpleIPCServer.GetInstanceID: String; function TSimpleIPCServer.GetInstanceID: String;
begin begin
Result:=FIPCComm.InstanceID; Result:=FIPCComm.InstanceID;
@ -498,6 +527,11 @@ begin
Result:=FQueue.MaxAction; Result:=FQueue.MaxAction;
end; end;
function TSimpleIPCServer.GetMaxQueue: Integer;
begin
Result:=FQueue.MaxCount;
end;
function TSimpleIPCServer.GetStringMessage: String; function TSimpleIPCServer.GetStringMessage: String;
begin begin
@ -505,7 +539,7 @@ begin
end; end;
procedure TSimpleIPCServer.StartServer; procedure TSimpleIPCServer.StartServer(Threaded : Boolean = False);
begin begin
if Not Assigned(FIPCComm) then if Not Assigned(FIPCComm) then
begin begin
@ -515,10 +549,62 @@ begin
FIPCComm.StartServer; FIPCComm.StartServer;
end; end;
FActive:=True; FActive:=True;
If Threaded then
StartThread;
end;
Type
{ TServerThread }
TServerThread = Class(TThread)
private
FServer: TSimpleIPCServer;
FThreadTimeout: Integer;
Public
Constructor Create(AServer : TSimpleIPCServer; ATimeout : integer);
procedure Execute; override;
Property Server : TSimpleIPCServer Read FServer;
Property ThreadTimeout : Integer Read FThreadTimeout;
end;
{ TServerThread }
constructor TServerThread.Create(AServer: TSimpleIPCServer; ATimeout: integer);
begin
FServer:=AServer;
FThreadTimeout:=ATimeOut;
Inherited Create(False);
end;
procedure TServerThread.Execute;
begin
While Not Terminated do
FServer.PeekMessage(ThreadTimeout,False);
end;
procedure TSimpleIPCServer.StartThread;
begin
InitCriticalSection(FLock);
FThread:=TServerThread.Create(Self,ThreadTimeOut);
end;
procedure TSimpleIPCServer.StopThread;
begin
if Assigned(FThread) then
begin
FThread.Terminate;
FThread.WaitFor;
FreeAndNil(FThread);
DoneCriticalSection(FLock);
end;
end; end;
procedure TSimpleIPCServer.StopServer; procedure TSimpleIPCServer.StopServer;
begin begin
StopThread;
If Assigned(FIPCComm) then If Assigned(FIPCComm) then
begin begin
FIPCComm.StopServer; FIPCComm.StopServer;
@ -529,7 +615,7 @@ begin
end; end;
// TimeOut values: // TimeOut values:
// > 0 -- umber of milliseconds to wait // > 0 -- Number of milliseconds to wait
// = 0 -- return immediately // = 0 -- return immediately
// = -1 -- wait infinitely // = -1 -- wait infinitely
// < -1 -- wait infinitely (force to -1) // < -1 -- wait infinitely (force to -1)
@ -557,9 +643,17 @@ function TSimpleIPCServer.PopMessage: Boolean;
var var
MsgItem: TIPCServerMsg; MsgItem: TIPCServerMsg;
DoLock : Boolean;
begin begin
MsgItem:=FQueue.Pop; DoLock:=Assigned(FThread);
if DoLock then
EnterCriticalsection(Flock);
try
MsgItem:=FQueue.Pop;
finally
LeaveCriticalsection(FLock);
end;
Result:=Assigned(MsgItem); Result:=Assigned(MsgItem);
if Result then if Result then
try try
@ -605,6 +699,55 @@ begin
end; end;
procedure TSimpleIPCServer.DoMessageQueued;
begin
if Assigned(FOnMessageQueued) then
FOnMessageQueued(Self);
end;
procedure TSimpleIPCServer.DoMessageError;
begin
try
if Assigned(FOnMessageQueued) then
FOnMessageError(Self,FErrMsg);
finally
FreeAndNil(FErrMsg)
end;
end;
procedure TSimpleIPCServer.PushMessage(Msg: TIPCServerMsg);
Var
DoLock : Boolean;
begin
try
DoLock:=Assigned(FThread);
If DoLock then
EnterCriticalsection(FLock);
try
Queue.Push(Msg);
finally
If DoLock then
LeaveCriticalsection(FLock);
end;
if DoLock then
TThread.Synchronize(FThread,@DoMessageQueued)
else
DoMessageQueued;
except
On E : Exception do
FErrMsg:=Msg;
end;
if Assigned(FErrMsg) then
if DoLock then
TThread.Synchronize(FThread,@DoMessageError)
else
DoMessageQueued;
end;
{ --------------------------------------------------------------------- { ---------------------------------------------------------------------

View File

@ -229,11 +229,6 @@ begin
Result:=TPipeServerComm; Result:=TPipeServerComm;
end; end;
procedure TSimpleIPCServer.PushMessage(Msg: TIPCServerMsg);
begin
Queue.Push(Msg);
end;
function TSimpleIPCClient.CommClass: TIPCClientCommClass; function TSimpleIPCClient.CommClass: TIPCClientCommClass;
begin begin
if (DefaultIPCClientClass<>Nil) then if (DefaultIPCClientClass<>Nil) then