سؤال

تم إهمال طريقة استئناف TThread في D2010.لذا، اعتقدت أن الأمر يجب أن يعمل الآن على النحو التالي:

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

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

لسوء الحظ، أحصل على استثناء "لا يمكن الاتصال بالبدء في سلسلة رسائل قيد التشغيل أو معلقة"... والذي يبدو غريبًا بالنسبة لي بالنظر إلى حقيقة أن الوثائق تخبرني أنه يجب علي الاتصال بـ Start على سلسلة رسائل تم إنشاؤها في الوضع المرحلي.

ما الذي أفتقده هنا؟

هل كانت مفيدة؟

المحلول

والسبب هو أن أ خيط ليس من المفترض أن يبدأ من تلقاء نفسه.

لا يعرف مؤشر الترابط أبدًا متى تكتمل التهيئة.الإنشاء ليس مثل التهيئة (يجب أن يكون الإنشاء دائمًا قصيرًا وخاليًا من الاستثناءات؛تتم المزيد من التهيئة بعد البناء).

حالة مماثلة هي أ TDataSet:لا TDataSet يجب على المنشئ الاتصال على الإطلاق يفتح, ، أو تعيين نشيط:= صحيح.

أنظر هذا أيضا دخول بلوق من قبل أجنحة الرياح.

يجب عليك إما:

  • قم بإنشاء TMyThread المعلق عن طريق الاتصال بـ Create(true) وقم بإجراء البدء خارج فئة TMyThread الخاصة بك
  • قم بإنشاء TMyThread غير معلق، مع التأكد من أن مُنشئ الإنشاء يقوم بالتهيئة الكاملة، واترك TThread.AfterConstruction ابدأ الخيط.

شرح استخدام 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.

--جيروين

نصائح أخرى

والجواب باختصار: دعوة رثت خلق (كاذبة) وomitt البداية!

ويتم البدء الفعلي للموضوع غير علقت إنشاء في AfterConstruction، وهو ما يسمى بعد أن تم استدعاء جميع الصانعين.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top