I want to check the following code, in particular Execute method,to ensure it's not doing anything super dodgy. This code is Delphi 2007, btw.
I am passing back to the main thread via synchronize a reference to an object (FToken) created in the execute method of the thread.
I am only doing this after the FToken is created in TTokenThread.Execute
Is this OK in terms of thread safety?
Critique most welcome.
Type
TExceptionNotifyEvent = procedure(Const Error : String) of object;
TTokenNotifyEvent = procedure(const Token : AccessToken) of object;
TTokenThread = class(TThread)
private
FTokenNotifyEvent : TTokenNotifyEvent;
FOnException : TExceptionNotifyEvent;
FExceptionMsg : String;
FToken : AccessToken;
procedure HandleException(const E : Exception);
procedure DoException;
procedure DoSynchronise;
public
constructor Create;
destructor Destroy;override;
procedure Execute; override;
procedure WhenException(const OnException : TExceptionNotifyEvent);
procedure WhenToken(const TokenNotify : TTokenNotifyEvent);
end;
{ TTokenThread }
constructor TTokenThread.Create;
begin
inherited create(true);
FreeOnTerminate := true;
end;
destructor TTokenThread.Destroy;
begin
if assigned(FToken) then FToken.free;
inherited;
end;
procedure TTokenThread.Execute;
begin
inherited;
try
FToken := RESTAdapter.GetAccessToken();
synchronize(DoSynchronise);
except on
E:Exception do
begin
handleException(E);
end;
end;
end;
procedure TTokenThread.HandleException(const E: Exception);
begin
if terminated then exit;
FExceptionMsg := E.Message;
synchronize(DoException); //synch call with the main thread (this is potentially blocking)
Terminate;
end;
procedure TTokenThread.WhenException(const OnException: TExceptionNotifyEvent);
begin
FOnException := OnException;
end;
procedure TTokenThread.WhenToken(const TokenNotify: TTokenNotifyEvent);
begin
FTokenNotifyEvent := TokenNotify;
end;
procedure TTokenThread.DoException ;
begin
if assigned(FOnException) then FOnException(FExceptionMsg);
end;
procedure TTokenThread.DoSynchronise;
begin
if assigned(FTokenNotifyEvent) and assigned(FToken) then FTokenNotifyEvent(FToken);
end;
calling code
procedure TForm3.ProcessToken(const Token : AccessToken);
begin
if assigned(Token) then
begin
memo1.lines.clear;
memo1.lines.add(format('access_token: %s',[Token.Token]));
memo1.lines.add(format('expires_in: %s',[inttostr(Token.ExpiryUtc)]));
memo1.lines.add(format('token_type: %s',[token.type2]));
memo1.lines.add(format('scope: %s',[token.scope]));
end;
end;
procedure TForm3.BtnAccessTokenClick(Sender: TObject);
var
TokenThread : TTokenThread;
begin
TokenThread := TTokenThread.create;
TokenThread.WhenToken(ProcessToken);
TokenThread.Resume;
end;