델파이 2010에서 스레드 스레드를 재개 하시겠습니까?
-
06-07-2019 - |
문제
TTHREAD의 이력서 방법은 D2010에서 더 이상 사용되지 않습니다. 그래서 이제는 다음과 같이 작동해야한다고 생각했습니다.
TMyThread = class (TThread)
protected
Execute; override;
public
constructor Create;
end;
...
TMyThread.Create;
begin
inherited Create (True);
...
Start;
end;
불행히도 나는 "실행 또는 대체 된 스레드에서 시작을 호출 할 수 없다"는 예외를 얻는다. 이는 문서가 일시 중단 모드에서 생성 된 스레드에서 시작을 호출해야한다는 사실을 고려하여 나에게 이상하게 보인다.
내가 여기서 무엇을 놓치고 있습니까?
해결책
스레드는 초기화가 완료된시기를 결코 알 수 없습니다. 시공은 초기화와 동일하지 않습니다 (건설은 항상 짧고 예외가 없어야합니다. 건설 후 추가 초기화가 이루어집니다).
비슷한 상황은 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) 및 시작을 생략하십시오!
비가 부족한 스레드의 실제 시작은 애프터 건설에서 수행되며, 모든 생성자가 호출 된 후 호출됩니다.