标签: tthread

一种破坏TThread对象的正确方法

这个问题似乎微不足道,但我希望你不要忽视它.
在销毁TThread对象之前,通常需要等到调用TThread.Execute()方法的线程完成,因为只有这样我们才能确定,例如,不再访问在类的析构函数中销毁的对象.因此,有必要调用Terminate来设置线程必须检查的Terminated标志以知道是否退出,然后调用WaitFor()方法.

因为线程可能被挂起,我认为在调用WaitFor之前恢复它是好的,否则调用线程将会死锁.并且因为线程可以多次挂起,所以应该恢复相同的次数,对吗?

while Suspended do
  Resume;
Run Code Online (Sandbox Code Playgroud)

如果线程被创建为暂停,我们不必担心当我们恢复线程只会终止它时将调用TThread.Execute()方法 - 它不会(如果我错了请纠正我).

我所说的建议为每个被释放的TThread对象使用以下代码行:

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;
Run Code Online (Sandbox Code Playgroud)

不幸的是,当我们销毁创建多个线程的应用程序时,为每个被破坏的TThread对象编写这样一段代码会使代码变得非常长,甚至可能不透明.

因此我得出结论,所有这些都可以放在TThread类的重写析构函数中,这要归功于调用MyThread.Free(如果设置了MyThread.FreeOnTerminate,则调用MyThread.Terminate),而不关心是否销毁object是否是TThread对象:

destructor TMyThread.Destroy;
begin
  //if FreeOnTerminate, the calling thread cannot wait for itself
  if GetCurrentThreadId <> ThreadId then
  begin
    Terminate;
    while Suspended do
      Resume;
    WaitFor;
  end;

  {free all objects created in this class}

  inherited Destroy;
end;
Run Code Online (Sandbox Code Playgroud)

请原谅我提出这样一个基本问题.但是,我希望通过这种方式了解您的意见 - 我希望这是一种普遍的方式 - 销毁TThread对象.我问这个问题,因为我从我的同事的代码中学到了他们通常使用第一个代码示例来销毁这些对象,但他们从来没有用来检查等待的线程是否没有被挂起,如果线程我认为有点危险可能会在代码中的某处暂停.因此,我试图找到一种破坏这个类的对象的通用方法,这将使代码更清晰,更安全.我希望我没有让情况变得更糟 - 你怎么看?

提前感谢您的建议.

delphi destructor tthread

16
推荐指数
2
解决办法
1万
查看次数

我应该用什么delphi代码替换我对不推荐使用的TThread方法Suspend的调用?

之前有人问过,但没有完整答案.这与所谓的着名"'致命线程模型!'"有关.

我需要用安全的东西替换这个调用TThread.Suspend,当终止或恢复时返回:

procedure TMyThread.Execute;
begin
  while (not Terminated) do begin
     if PendingOffline then begin
          PendingOffline := false;   // flag off.
          ReleaseResources;
          Self.Suspend; // suspend thread. { evil! ask Barry Kelly why.}
          // -- somewhere else, after a long time, a user clicks
          // a resume button, and the thread resumes: --
          if Terminated then
              exit; // leave TThread.Execute.
          // Not terminated, so we continue..
          GrabResources;
     end;
    end;
end;
Run Code Online (Sandbox Code Playgroud)

最初的答案含糊地暗示了"TMutex,TEvent和关键部分".

我想我正在寻找一个TThreadThatDoesntSuck.

以下是带有Win32Event的TThread派生示例,供评论:

unit SignalThreadUnit;

interface

uses
  Classes,SysUtils,Windows;

type

TSignalThread …
Run Code Online (Sandbox Code Playgroud)

delphi tthread

16
推荐指数
2
解决办法
5543
查看次数

使用TThread.Resume有什么问题?

很久以前,当我开始使用Delphi中的线程时,我通过TThread.Resume在构造函数的末尾调用来创建线程,并且仍然如此:

constructor TMyThread.Create(const ASomeParam: String);
begin
  inherited Create(True);
  try
    FSomeParam:= ASomeParam;
    //Initialize some stuff here...
  finally
    Resume;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

从那时起,Resume一直被弃用Start而不是使用.但是,Start只能从线程外部调用,并且不能从构造函数内部调用.

我继续使用Resume如上所示设计我的线程,虽然我知道它已被弃用 - 只是因为我不想Start从线程外部调用.我发现要打电话有点乱:

FMyThread := TMyThread.Create(SomeParamValue);
FMyThread.Start;
Run Code Online (Sandbox Code Playgroud)

问题:这个改变的原因是什么?我的意思是,使用Resume他们希望我们使用它的错误是什么Start

编辑在Sedat的回答之后,我想这实际上取决于在构造函数中,线程实际开始执行的时间.

delphi multithreading tthread deprecated

14
推荐指数
1
解决办法
844
查看次数

如何实现使用最少资源定期检查某些内容的线程?

我想在后台运行一个线程,它将以给定的时间间隔检查与某个服务器的连接.例如每5秒.

我不知道这是否有一个好的"设计模式"?如果我记得正确的话,我已经读过一些在其执行方法中睡眠线程不好的地方.但我可能错了.

另外,我可以使用普通的TThread类或OTL线程库.

有任何想法吗?

谢谢.

delphi multithreading tthread delphi-2009 omnithreadlibrary

13
推荐指数
2
解决办法
2476
查看次数

使用FreeOnTerminate = True的TThread的Delphi单元测试

当FreeOnTerminate = True时,为TThread后代编写Delphi DUnit测试的最佳方法是什么?TThread后代返回一个我需要测试的引用,但我无法弄清楚如何等待线程在测试中完成...

unit uThreadTests;

interface

uses
  Classes, TestFramework;

type

  TMyThread = class(TThread)
  strict private
    FId: Integer;
  protected
    procedure Execute; override;
  public
    constructor Create(AId: Integer);
    property Id: Integer read FId;
  end;

  TestTMyThread = class(TTestCase)
  strict private
    FMyId: Integer;
    procedure OnThreadTerminate(Sender: TObject);
  protected
    procedure SetUp; override;
    procedure TearDown; override;
  published
    procedure TestMyThread;
  end;

implementation

{ TMyThread }

constructor TMyThread.Create(AId: Integer);
begin
  FreeOnTerminate := True;
  FId := AId;

  inherited Create(False);
end;

procedure TMyThread.Execute;
begin
  inherited;

  FId := FId + 1;
end; …
Run Code Online (Sandbox Code Playgroud)

delphi unit-testing dunit tthread delphi-2010

12
推荐指数
1
解决办法
4500
查看次数

Delphi TThread.CurrentThread和EAccessViolation - 这是一个错误还是我的无能......?

在Delphi 2009中,我发现无论何时在应用程序中使用TThread.CurrentThread,我都会在应用程序关闭时收到如下错误消息:

Exception EAccessViolation in module ntdll.dll at 0003DBBA.
Access violation at address 7799DBBA in module 'ntdll.dll'.  Write of
address 00000014.
Run Code Online (Sandbox Code Playgroud)

除非它只是我的机器,你可以在几秒钟内复制它:创建一个新的Delphi Forms Application,在表单中添加一个按钮,并使用类似下面的按钮的事件处理程序:

procedure TForm1.Button1Click(Sender: TObject);
begin
  TThread.CurrentThread;
end;
Run Code Online (Sandbox Code Playgroud)

在我的Vista的机器和我的XP的机器都我发现,如果我按一下按钮一切都很好,但如果我做的点击按钮,我得到上面的错误消息,当我关闭应用程序.

所以...我想知道这是不是一个错误,但与此同时我认为我很可能根本不理解你应该如何在Delphi中使用TThreads.我有点像德尔福新手,我很害怕.

使用TThread.CurrentThread有什么明显错误吗?

如果没有,并且你有Delphi 2009,如果你实现我的简单示例项目,你会遇到同样的问题吗?


更新:正如François在下面提到的,这实际上是Delphi 2009中的一个错误 - 你可以在这里投票.


更新:此错误已在Delphi 2010中修复.

delphi tthread delphi-2009

11
推荐指数
3
解决办法
7660
查看次数

Delphi(XE2)Indy(10)多线程Ping

我有一个有60台计算机/设备的房间(40台计算机和20台基于Windows CE的示波器),我想知道哪个和每个人都在使用ping.首先我写了一个标准的ping(请参阅此处Delphi Indy Ping错误10040),现在工作正常,但大多数计算机脱机时需要很长时间.

所以我要做的就是编写一个MultiThread Ping,但我很挣扎.我在互联网上看到的例子很少,没有人能满足我的需求,这就是为什么我自己尝试写这个例子.

我使用XE2和Indy 10,表单只包含备忘录和按钮.

unit Main;

interface

uses
  Winapi.Windows, System.SysUtils, System.Classes, Vcl.Forms,
  IdIcmpClient, IdGlobal, Vcl.StdCtrls, Vcl.Controls;

type
  TMainForm = class(TForm)
    Memo1: TMemo;
    ButtonStartPing: TButton;
    procedure ButtonStartPingClick(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

type
  TMyPingThread = class(TThread)
  private
    fIndex : integer;
    fIdIcmpClient: TIdIcmpClient;
    procedure doOnPingReply;
  protected
    procedure Execute; override;
  public
    constructor Create(index: integer);
  end;

var
  MainForm: TMainForm;
  ThreadCOunt : integer;

implementation

{$R *.dfm}

constructor TMyPingThread.Create(index: integer);
begin
  inherited Create(false); …
Run Code Online (Sandbox Code Playgroud)

delphi multithreading ping indy tthread

11
推荐指数
2
解决办法
1万
查看次数

如何在后台线程中使用LoadKeyboardLayout?

我正在使用LoadKeyboardLayout函数以这种方式加载和激活键盘布局:

procedure TfrmMain.eSearchEnter(Sender: TObject);
begin
  LoadKeyboardLayout('00000429', KLF_ACTIVATE);
end;
Run Code Online (Sandbox Code Playgroud)

它工作得很好,但它冻结活动形式1-2秒,因为这种变化需要一些时间.为了防止这种情况,我将此代码移动到这样的后台线程:

type
  FLangChangeThread = class(TThread)
  private
    FLang: string;
  protected
    procedure Execute; override;
  public
    property Lang: string read FLang write FLang;
  end;

implementation

procedure FLangChangeThread.Execute;
begin
  if FLang = 'EN' then
    LoadKeyboardLayout('00000409', KLF_ACTIVATE)
  else
  if FLang = 'FA' then
    LoadKeyboardLayout('00000429', KLF_ACTIVATE);
end;
Run Code Online (Sandbox Code Playgroud)

这个后台线程我正在以这种方式运行:

procedure TfrmMain.ChangeWritingLanguage(ALang: string);
begin
  with FLangChangeThread.Create(True) do
  begin
    FreeOnTerminate := True;
    Lang := ALang;
    Resume;
  end;
end;

procedure TfrmMain.eSearchEnter(Sender: TObject);
begin
  ChangeWritingLanguage('FA');
end;
Run Code Online (Sandbox Code Playgroud)

问题是,它没有按预期更改键盘布局.我调试了代码并且所有行都被执行了; 只是LoadKeyboardLayout函数没有完成它的工作.

如何从后台线程使 …

delphi tthread keyboard-layout

10
推荐指数
1
解决办法
2636
查看次数

自动或手动释放TThread

我的程序中有一个主线程和一个单独的线程.如果单独的线程在主线程之前完成,它应该自动释放.如果主线程首先完成,它应该释放单独的线程.

我知道FreeOnTerminate,我读过你必须小心使用它.

我的问题是,以下代码是否正确?

procedure TMyThread.Execute;
begin
  ... Do some processing

  Synchronize(ThreadFinished);

  if Terminated then exit;

  FreeOnTerminate := true;
end;

procedure TMyThread.ThreadFinished;
begin
  MainForm.MyThreadReady := true;
end;

procedure TMainForm.Create;
begin
  MyThreadReady := false;

  MyThread := TMyThread.Create(false);
end;

procedure TMainForm.Close;
begin
  if not MyThreadReady then
  begin
    MyThread.Terminate;
    MyThread.WaitFor;
    MyThread.Free;
  end;
end;
Run Code Online (Sandbox Code Playgroud)

delphi multithreading delphi-7 tthread

9
推荐指数
2
解决办法
5299
查看次数

在TThread执行中引发异常?

我刚刚意识到我的异常没有在我的线程中向用户显示!

起初我在我的线程中使用它来引发异常,这不起作用:

except on E:Exception do
begin
  raise Exception.Create('Error: ' + E.Message);
end;
Run Code Online (Sandbox Code Playgroud)

IDE向我显示了异常,但我的应用程序没有!

我四处寻找解决方案,这就是我发现的:

Delphi线程异常机制

http://www.experts-exchange.com/Programming/Languages/Pascal/Delphi/Q_22039681.html

这些都不适合我.

这是我的Thread单元:

unit uCheckForUpdateThread;

interface

uses
  Windows, IdBaseComponent, IdComponent, IdTCPConnection, IdTCPClient,
  IdHTTP, GlobalFuncs, Classes, HtmlExtractor, SysUtils, Forms;

type
  TUpdaterThread = class(TThread)
  private
    FileGrabber : THtmlExtractor;
    HTTP : TIdHttp;
    AppMajor,
    AppMinor,
    AppRelease : Integer;
    UpdateText : string;
    VersionStr : string;
    ExceptionText : string;
    FException: Exception;
    procedure DoHandleException;
    procedure SyncUpdateLbl;
    procedure SyncFinalize;
  public
    constructor Create;

  protected
    procedure HandleException; virtual;

    procedure Execute; override;
  end;

implementation

uses …
Run Code Online (Sandbox Code Playgroud)

delphi multithreading exception raise tthread

8
推荐指数
3
解决办法
4033
查看次数