【问题标题】:Custom Thread misbehaving自定义线程行为不端
【发布时间】:2014-01-10 17:35:11
【问题描述】:

给定以下类:

type

    GEvent = class(TThread)
    public
        procedure Terminate;
        procedure Call(Event : GEvent);
        constructor Create;
        procedure Execute; Override;

    end;


    TDirection = (DUp, DRight, DDown, DLeft);

    EventTitle = class(GEvent)
    private
        Index : Integer;
        Sprite : CSprite;
        Terminate : Boolean;
        procedure CreateSprite;
        procedure MoveCursor(Direction : TDirection);
        procedure RefreshCursor;
        constructor Create;
        destructor Destroy;
    public
        procedure Execute;
    end;

implementation


{ GEvent }

procedure GEvent.Call(Event: GEvent);
begin
    Suspend;
//    inherited Terminate;
    Self := GEvent(Event.ClassType.Create);
end;

constructor GEvent.Create;
begin
    inherited Create(True);
end;

destructor GEvent.Destroy;
begin
    Terminate;
    inherited;
end;

procedure GEvent.Execute;
begin
   // inherited;
end;

procedure GEvent.Terminate;
begin
    Suspend;
    inherited;
end;

{ EventTitle }

constructor EventTitle.Create;
begin
    inherited;
    Resume;
end;

procedure EventTitle.CreateSprite;
begin
    Showmessage('anything');
end;

destructor EventTitle.Destroy;
begin

  inherited;
end;

procedure EventTitle.Execute;
begin
    inherited;
    Synchronize(CreateSprite);
    Index := 0; {
    while not Terminated do
    begin
        if GISystem.System.Input.Trigger(KUp) then
            MoveCursor(DUp);
        if GISystem.System.Input.Trigger(KDown) then
            MoveCursor(DDown);
    end;   }
end;

当主窗体自动调用InstanceVar := EventTitle.Create 时,线程应该到达方法CreateSprite,奇怪的是没有发生。我不明白为什么该方法没有被执行。应用程序的主要形式仍然可以正常工作,但似乎EventTitle.Execute 突然停止甚至不启动。这也可能是错误的实现。这是我的第一次多线程试验,如有任何不一致之处,请见谅。谁能看到我做错了什么?

【问题讨论】:

  • OT:不要使用SuspendResume。它们已被弃用,因为编译器会在警告中向您报告...同时将线程创建为挂起并立即恢复看起来并没有多大用处。
  • 真的。我会让Resume 给子线程。删除它...
  • 也许使用 OmniThreadLibrary 比深入研究 TThread 内部更容易

标签: multithreading delphi delphi-xe3


【解决方案1】:

这里有一些明显的问题。我不确定修复它们是否会解决您的问题,但我不会感到惊讶:

  1. 您的Execute 方法必须用override 声明才能运行。这解释了您报告的行为。
  2. 您的析构函数必须用override 声明才能运行。请注意,您实现了GEvent.Destroy,但GEvent 类没有声明析构函数。所以问题中的代码无法编译。
  3. 不要在线程类的析构函数中调用Terminate。基类析构函数TThread.Destroy 终止并等待线程。在GEvent.Destroy 中删除对Terminate 的调用。
  4. 您的Terminate 方法隐藏了TThread.Terminate。这真是不好的做法。我确定编译器会警告您这一点。你必须注意这些警告。就目前而言,您的线程的析构函数会挂起线程,然后等待它完成。您最好希望线程在您销毁它时已经执行完毕。
  5. 创建一个挂起的线程只是为了立即恢复它是没有意义的。虽然这不会造成真正的问题。
  6. GEvent.Call 中的代码完全是伪造的。永远不要分配给Self。您必须删除该代码。
  7. 您对Suspend 的所有调用都是错误的。您不得致电Suspend。它有不可预测的结果。删除对Suspend 的调用。

您犯的一个重复错误是遗漏了override。该关键字用于覆盖虚拟方法。对于Execute 方法和析构函数,这些是基类调用的虚拟方法。因此,如果您不覆盖虚拟方法,那么您只是在派生类中引入了一个新方法。而且当基类调用虚方法时,你的新方法不会执行。

我建议你从这段代码开始:

type
  EventTitle = class(TThread)
  private
    procedure DoSomething;
  public
    constructor Create;
    procedure Execute; override;
  end;

implementation

constructor EventTitle.Create;
begin
  inherited Create(False);
end;

procedure EventTitle.DoSomething;
begin
  ShowMessage('anything');
end;

procedure EventTitle.Execute;
begin
  Synchronize(DoSomething);
end;

我已经删除了您的几乎所有代码,但几乎所有代码都是错误的。

【讨论】:

  • 1.那好吧。 2.GEvent会有很多孩子;其中一些可能需要一些初始化的东西。但是这里也一切正常。 3. 此代码引用另一个具有GEvent 属性的类。此属性将在使用 Call 方法的事件之间更改,但我正在努力删除该行。这不是问题的原因。 4. 删除所有Suspend 呼叫。问题依然存在。
  • 我猜Override 不见了。一旦我覆盖了GEvent 类,我认为我不必在它的孩子中做。我在 Delphi 中关于 Threading 的页面中没有找到这个约定。它们是非常必要的。不管怎样,谢谢楼主。我接受你的回答。我还不能投票所以...
  • 该问题与线程无关。这纯粹是与虚拟方法解析有关的语言问题。您不会期望在有关线程的文章中找到讨论的内容。你会在语言指南中找到它的详细信息。很好的阅读。
  • 我会试试的。谢谢!
猜你喜欢
  • 2019-06-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-28
  • 2012-10-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多