Frage

TThread Lebenslauf Methode wird in D2010 veraltet. Also, ich dachte, es sollte nun wie folgt funktionieren:

TMyThread = class (TThread)
protected
  Execute; override;
public
  constructor Create;
end;
...

TMyThread.Create;
begin
  inherited Create (True);
  ...
  Start;
 end;

Leider bekomme ich eine Ausnahme „nenne, kann nicht auf einem laufendes oder supsended Thread starten“ ... die ich seltsam scheint in Anbetracht die Tatsache, dass die Dokumentation mir sagt, dass ich Anfang an einem Faden in angehaltenem Modus erstellt rufen soll.

Was bin ich hier fehlt?

War es hilfreich?

Lösung

Der Grund hierfür ist, dass ein Thema ist eigentlich nicht sich selbst starten .

Der Faden nie weiß, wann die Initialisierung abgeschlossen ist. Die Konstruktion ist nicht das gleiche wie die Initialisierung (Konstruktion sollte immer kurz und Ausnahme frei, weitere Initialisierung nach dem Bau durchgeführt).

Eine ähnliche Situation ist ein TDataSet : no TDataSet Konstruktor sollte jemals rufen Öffnen , oder setzen Sie Aktiv: = True .

Siehe auch diesen Blog-Eintrag von Wings of Wind .

Sie sollten entweder:

  • Erstellen Sie das suspendiert TMyThread von Create (true) aufrufen und den Start außerhalb Ihrer TMyThread Klasse durchführt
  • Erstellen Sie die TMyThread nicht-suspeneded, die sicherstellen, dass Erstellen Konstruktor tut Vollinitialisierung, und lassen Sie TThread.AfterConstruction den Thread starten.

Erklärung der TThread Nutzung :

Grundsätzlich sollte ein Faden sein, nur, dass: die Einkapselung des Kontextes, auf dem der Code ausgeführt wird

.

Der eigentliche Code (die Business-Logik), die dann in anderen Klassen ausgeführt wird, soll.

diese beiden Durch die Entkopplung, Sie viel Flexibilität gewinnen, vor allem Ihre Geschäftslogik aus mehreren Stellen initiieren (was sehr praktisch ist, wenn Unit-Tests zu schreiben!).

Dies ist die Art von Rahmen, den Sie dafür verwenden können:

unit DecoupledThreadUnit;

interface

uses
  Classes;

type
  TDecoupledThread = class(TThread)
  strict protected
    //1 called in the context of the thread
    procedure DoExecute; virtual;
    //1 Called in the context of the creating thread (before context of the new thread actualy lives)
    procedure DoSetUp; virtual;
    //1 called in the context of the thread right after OnTerminate, but before the thread actually dies
    procedure DoTearDown; virtual;
  protected
    procedure DoTerminate; override;
    procedure Execute; override;
  public
    constructor Create;
    procedure AfterConstruction; override;
  end;

implementation

constructor TDecoupledThread.Create;
begin
  // create suspended, so that AfterConstruction can call DoSetup();
  inherited Create(True);
end;

procedure TDecoupledThread.AfterConstruction;
begin
  // DoSetUp() needs to be called without the new thread in suspended state
  DoSetUp();
  // this will unsuspend the underlying thread
  inherited AfterConstruction;
end;

procedure TDecoupledThread.DoExecute;
begin
end;

procedure TDecoupledThread.DoSetUp;
begin
end;

procedure TDecoupledThread.DoTearDown;
begin
end;

procedure TDecoupledThread.DoTerminate;
begin
  inherited DoTerminate();
  // call DoTearDown on in the thread context right before it dies:
  DoTearDown();
end;

procedure TDecoupledThread.Execute;
begin
  // call DoExecute on in the thread context
  DoExecute();
end;

end.

Sie könnten sogar Ereignis machen es anhand von so etwas wie folgt aus:

unit EventedThreadUnit;

interface

uses
  Classes,
  DecoupledThreadUnit;

type
  TCustomEventedThread = class(TDecoupledThread)
  private
    FOnExecute: TNotifyEvent;
    FOnSetUp: TNotifyEvent;
    FOnTearDown: TNotifyEvent;
  strict protected
    procedure DoExecute; override;
    procedure DoSetUp; override;
    procedure DoTearDown; override;
  public
    property OnExecute: TNotifyEvent read FOnExecute write FOnExecute;
    property OnSetUp: TNotifyEvent read FOnSetUp write FOnSetUp;
    property OnTearDown: TNotifyEvent read FOnTearDown write FOnTearDown;
  end;

  // in case you want to use RTTI
  TEventedThread = class(TCustomEventedThread)
  published
    property OnExecute;
    property OnSetUp;
    property OnTearDown;
  end;

implementation

{ TCustomEventedThread }

procedure TCustomEventedThread.DoExecute;
var
  TheOnExecute: TNotifyEvent;
begin
  inherited;
  TheOnExecute := OnExecute;
  if Assigned(TheOnExecute) then
    TheOnExecute(Self);
end;

procedure TCustomEventedThread.DoSetUp;
var
  TheOnSetUp: TNotifyEvent;
begin
  inherited;
  TheOnSetUp := OnSetUp;
  if Assigned(TheOnSetUp) then
    TheOnSetUp(Self);
end;

procedure TCustomEventedThread.DoTearDown;
var
  TheOnTearDown: TNotifyEvent;
begin
  inherited;
  TheOnTearDown := OnTearDown;
  if Assigned(TheOnTearDown) then
    TheOnTearDown(Self);
end;

end.

oder anpassen es für DUnit TTestCase Nachkommen wie folgt aus:

unit TestCaseThreadUnit;

interface

uses
  DecoupledThreadUnit,
  TestFramework;

type
  TTestCaseRanEvent = procedure (Sender: TObject; const TestResult: TTestResult) of object;
  TTestCaseThread = class(TDecoupledThread)
  strict private
    FTestCase: TTestCase;
  strict protected
    procedure DoTestCaseRan(const TestResult: TTestResult); virtual;
    function GetTestCase: TTestCase; virtual;
    procedure SetTestCase(const Value: TTestCase); virtual;
  protected
    procedure DoExecute; override;
    procedure DoSetUp; override;
    procedure DoTearDown; override;
  public
    constructor Create(const TestCase: TTestCase);
    property TestCase: TTestCase read GetTestCase write SetTestCase;
  end;

implementation

constructor TTestCaseThread.Create(const TestCase: TTestCase);
begin
  inherited Create();
  Self.TestCase := TestCase;
end;

procedure TTestCaseThread.DoExecute;
var
  TestResult: TTestResult;
begin
  if Assigned(TestCase) then
  begin
    // this will call SetUp and TearDown on the TestCase
    TestResult := TestCase.Run();
    try
      DoTestCaseRan(TestResult);
    finally
      TestResult.Free;
    end;
  end
  else
    inherited DoExecute();
end;

procedure TTestCaseThread.DoTestCaseRan(const TestResult: TTestResult);
begin
end;

function TTestCaseThread.GetTestCase: TTestCase;
begin
  Result := FTestCase;
end;

procedure TTestCaseThread.SetTestCase(const Value: TTestCase);
begin
  FTestCase := Value;
end;

procedure TTestCaseThread.DoSetUp;
begin
  if not Assigned(TestCase) then
    inherited DoSetUp();
end;

procedure TTestCaseThread.DoTearDown;
begin
  if not Assigned(TestCase) then
    inherited DoTearDown();
end;

end.

- jeroen

Andere Tipps

Kurze Antwort: Create (false) erbte und omitt Start!

Der tatsächliche Beginn eines nicht-create-suspendierte Fadens wird in Afterconstruction getan, die nach allen Konstrukteuren genannt wurden aufgerufen wird.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top