在D2010中不推荐使用TThread的简历方法。所以,我认为现在应该这样工作:
TMyThread = class (TThread)
protected
Execute; override;
public
constructor Create;
end;
...
TMyThread.Create;
begin
inherited Create (True);
...
Start;
end;
不幸的是我得到一个例外“无法在正在运行或已经上传的线程上调用start”...考虑到文档告诉我应该在以挂起模式创建的线程上调用Start这一事实,这对我来说似乎很奇怪。
我在这里缺少什么?
答案 0 :(得分:18)
The reason is that a Thread is not supposed to start itself
线程永远不知道初始化何时完成。构造与初始化不同(构造应始终短且无异常;构造后进一步初始化)。
类似的情况是 TDataSet :没有 TDataSet 构造函数应该调用打开,或者设置 Active:= True 强>
另见blog entry by Wings of Wind。
你应该:
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
答案 1 :(得分:14)
简答:调用继承Create(false)并省略Start!
非创建挂起线程的实际开始在AfterConstruction中完成,AfterConstruction在调用所有构造函数后调用。