ThreadingModel = tmFree) because it gives you total control over synchronization and optimization of your code. But writing thread-safe code also requires more work. In some cases, it may be useful to register your appserver to use the single-threaded apartment (STA) model (ThreadingModel = tmApartment) and rely on COM to serialize calls from different threads into one thread "apartment" - the same thread which was used to create the instance.Recently, after reviewing an external library I'm using in my appserver, and coming to suspect that it might not be thread-safe, I've chosen to use the STA model as a temporary workaround until I fix the problem.
Soon enough, I hit a problem - in the STA model, interface pointers cannot be freely passed from thread to thread - they need to be marshaled across thread boundaries, otherwise the call will fail with RPC_E_WRONG_THREAD error.
To marshal interface pointers across threads, you can use CoMarshalInterThreadInterfaceInStream . Another, very easy and convenient way is to aggregate the Free Threaded Marshaler.
Delphi makes aggregation a piece of cake! ;-) Here's a simple class which you can derive your appserver from (instead of deriving from
TRemoteDataModule directly):
unit DataBkrEx;
interface
uses
  Classes, ActiveX,
  DataBkr;
type
  TRemoteDataModuleEx = class(TRemoteDataModule, IMarshal)
  private
    FMarshal: IUnknown;
    function GetMarshal: IMarshal;
    property Marshal: IMarshal read GetMarshal implements IMarshal;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;
implementation
uses ComObj;
{ TRemoteDataModuleEx private }
function TRemoteDataModuleEx.GetMarshal: IMarshal;
begin
  if not Assigned(FMarshal) then
    OleCheck(CoCreateFreeThreadedMarshaler(Self as IUnknown, FMarshal));
  Result := FMarshal as IMarshal;
end;
{ TRemoteDataModuleEx public }
constructor TRemoteDataModuleEx.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FMarshal := nil;
end;
destructor TRemoteDataModuleEx.Destroy;
begin
  FMarshal := nil;
  inherited Destroy;
end;
end.
TComponentFactory in the VclCom unit.
No comments:
Post a Comment