문제

TTHREAD의 이력서 방법은 D2010에서 더 이상 사용되지 않습니다. 그래서 이제는 다음과 같이 작동해야한다고 생각했습니다.

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

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

불행히도 나는 "실행 또는 대체 된 스레드에서 시작을 호출 할 수 없다"는 예외를 얻는다. 이는 문서가 일시 중단 모드에서 생성 된 스레드에서 시작을 호출해야한다는 사실을 고려하여 나에게 이상하게 보인다.

내가 여기서 무엇을 놓치고 있습니까?

도움이 되었습니까?

해결책

그 이유는 a 스스로 시작해서는 안됩니다.

스레드는 초기화가 완료된시기를 결코 알 수 없습니다. 시공은 초기화와 동일하지 않습니다 (건설은 항상 짧고 예외가 없어야합니다. 건설 후 추가 초기화가 이루어집니다).

비슷한 상황은 a tdataset: 아니요 tdataset 생성자는 호출해야합니다 열려 있는, 또는 설정 Active : = true.

이것도 참조하십시오 날개의 블로그 항목.

당신은 다음 중 하나입니다 :

  • Create (True)를 호출하여 Speended를 작성하고 Tmythread 클래스 밖에서 시작을 수행하십시오.
  • tmythread를 사용하지 않는 tmythread를 만들고 생성자가 최대 초기화를 수행하고 TTHREAD 스레드를 시작하십시오.

tthread 사용에 대한 설명:

기본적으로 스레드는 바로 그 것입니다 : 코드가 실행되는 컨텍스트의 캡슐화.

실행 된 실제 코드 (비즈니스 로직)는 다른 클래스에 있어야합니다.

이 두 가지를 분리하면 많은 유연성을 얻을 수 있습니다. 특히 여러 장소 내에서 비즈니스 논리를 시작합니다 (단위 테스트를 작성할 때 매우 편리합니다!).

이것은 당신이 사용할 수있는 종류의 프레임 워크입니다.

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.

다음과 같은 것을 기반으로 이벤트를 만들 수도 있습니다.

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.

또는 다음과 같은 Dunit ttestcase 자손에 적응하십시오.

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

다른 팁

짧은 답변 : 호출 상속 된 생성 (false) 및 시작을 생략하십시오!

비가 부족한 스레드의 실제 시작은 애프터 건설에서 수행되며, 모든 생성자가 호출 된 후 호출됩니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top