Autor Beitrag
delfiphan
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: Sa 28.08.10 23:35 
Das Singleton-Pattern thread-safe korrekt zu implementieren ist nicht ganz einfach. Es wird häufig entweder über eine CriticalSection oder über Double Checked Locking implementiert. CriticalSections sind für diesen Zweck sehr langsam und Double Checked Locking kann je nach Compiler Schwierigkeiten bereiten. Mit den neuen APIs von Vista+ kann ein thread-safe Singleton einfach implementiert werden. Genau dazu ist diese Unit da.

msdn.microsoft.com/e...683493(v=VS.85).aspx

ausblenden volle Höhe Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
21:
22:
23:
24:
25:
26:
27:
28:
29:
30:
31:
32:
33:
34:
35:
36:
37:
38:
39:
40:
41:
42:
43:
unit InitializeOnce;

interface

type
  TInitializeOnce = class
  private
    FInit: Pointer;
    FOwnsObject: Boolean;
    function GetInstance: TObject;
  protected
    function DoInstantiate: TObject; virtualabstract;
  public
    destructor Destroy; override;
    property OwnsObject: Boolean read FOwnsObject write FOwnsObject;
    property Instance: TObject read GetInstance;
  end;

implementation

function InitOnceExecuteOnce(var InitOnce: Pointer; Callback: Pointer; Param: Pointer; var Context: Pointer): Boolean stdcallexternal 'kernel32.dll' name 'InitOnceExecuteOnce';

function InitHandleFunction(InitOnce: Pointer; Parameter: Pointer; var Context: Pointer): Boolean; stdcall;
begin
  Context := TInitializeOnce(Parameter).DoInstantiate;
  Result := True;
end;

{ TInitializeOnce }

destructor TInitializeOnce.Destroy;
begin
  if FOwnsObject and (FInit <> nilthen
    Instance.Free;
  inherited;
end;

function TInitializeOnce.GetInstance: TObject;
begin
  InitOnceExecuteOnce(FInit, @InitHandleFunction, Pointer(Self), Pointer(Result));
end;

end.
Marc.
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 1876
Erhaltene Danke: 129

Win 8.1, Xubuntu 15.10

BeitragVerfasst: So 29.08.10 15:08 
Hi!
ausblenden Delphi-Quelltext
 
26:
27:
28:
29:
30:
{ ... }
function InitHandleFunction(InitOnce: Pointer; Parameter: Pointer; var Context: Pointer): Boolean; stdcall;
begin
  Context := TInitializeOnce(Parameter).DoInstantiate;
  Result := True;
end;

Was genau bringt Result := True hier, außer den Compiler zu besänftigen, da die Funktion einen Rückgabewert erwartet?

Die Original-Funktion sieht, wenn ich das richtig recherchiert habe, so aus:
ausblenden C#-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
BOOL CALLBACK InitHandleFunction (
    PINIT_ONCE InitOnce,
    PVOID Parameter,
    PVOID *lpContext)
{

  HANDLE hEvent;

  hEvent = CreateEvent(NULL, TRUE, TRUE, NULL);

  if (NULL == hEvent)
  {
    return FALSE;
  }
  else
  {
    *lpContext = hEvent;
    return TRUE;
  }
}

Hier wird die Hilfsvariable hEvent zunächst auf NULL überprüft; je nach Ergebnis wird Context deren Wert anschließend zugewiesen.
Sollte es daher nicht in etwa wie folgt lauten:
ausblenden Delphi-Quelltext
1:
2:
3:
4:
5:
function InitHandleFunction(InitOnce: Pointer; Parameter: Pointer; var Context: Pointer): Boolean; stdcall;
begin
  Context := TInitializeOnce(Parameter).DoInstantiate;
  Result := Context <> nil;
end;


Beste Grüße,
Marc

Für diesen Beitrag haben gedankt: delfiphan
delfiphan Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 2684
Erhaltene Danke: 32



BeitragVerfasst: So 29.08.10 15:31 
Hi! Jo, ginge auch, ist vielleicht sogar ein bisschen besser, danke.

Bei Delphi erwarte ich bei einem Fehler in einer Factorymethode eher eine Exception, daher wird immer True zurückgegeben (oder eben eine Exception)