命名线程的最佳实践

时间:2014-04-28 14:28:19

标签: multithreading delphi debugging ide delphi-xe

最近我开发了一个高并发事件驱动框架(Java Akka),它将创建大量Actor个线程。当我调试Akka应用程序时,线程具有非常有意义的名称。它真的很棒。当我切换回Delphi时,我感到不安的是所有线程都没有命名,尽管它们在过去的20年里都没有命名。

对于我自己设计的所有线程类,我遵循这样一种模式,即定义一个setter SetThreadName,并在NameThreadForDebugging方法中调用Execute。这到目前为止工作正常。

type
  TMyThread = class(TThread)
  private
    FThreadName: string;
  protected
    procedure Execute; override;
  public
    procedure SetThreadName(const ThreadName: string);
  end;

procedure TMyThread.SetThreadName(const ThreadName: string);
begin
  FThreadName := ThreadName;
end;

procedure TMyThread.Execute;
begin
  NameThreadForDebugging(FThreadName);
  // Put normal thread execution code here
end;

但是,除非我创建了一个下降线程类,否则第三方线程的这些实例将保持未命名状态。是否有 Delphi Magic SetThreadName设置为基本Thread类?我可以使用Detour.pas强制在NameThreadForDebugging(FThreadName)方法的第一位调用Execute

有什么想法吗?


更新1 感谢David的亲切帮助。为了帮助其他读者更好地理解我的问题,这个问题已被重新改写。

  1. 我的代码出了什么问题?

    NameThreadForDebugging方法实际上是一种静态方法。第二个参数ThreadId是可选的,默认情况下它等于当前的线程ID。如果我没有清楚地给出ThreadId,我可能很可能命名当前的线程,而不是我真正想要命名的线程。

  2. 解决方案是什么?

    在任意位置拨打MyThread.NameThreadForDebugging('a_name', MyThread.ThreadId);或在NameThreadForDebugging('a_name');开头致电TMyThread.Execute

  3. 为什么如此困惑才能使事情正确?

    我不明白,为什么不在没有第二个ThreadId的情况下提供非静态版本。如果有这样的非静态版本,我就不会犯这个错误。

1 个答案:

答案 0 :(得分:7)

我在这里进行了扩展,但它看起来好像你认为只能从该线程内执行的代码中命名一个线程。但事实并非如此。为了命名一个线程,你只需要它的ID。

documentation给出了函数签名:

class procedure NameThreadForDebugging(AThreadName: AnsiString; 
  AThreadID: TThreadID = TThreadID(-1)); static;

如果您没有提供可选的线程ID参数,则传递-1,这被解释为含义,正在执行的线程。到目前为止,您使用NameThreadForDebugging的方式如何。但是,您只需传递线程ID即可。由于您明确拥有线程实例,因此您也可以拥有自己的ID。

您想象的接口涉及调用线程的实例方法传递线程的名称。那就是你想象写这段代码:

Thread.SetThreadName(ThreadName);

您可以简单地写下:

而不是这样做
TThread.NameThreadForDebugging(ThreadName, Thread.ThreadID);

如果您想使用类助手,可以这样做:

type
  TThreadHelper = class helper for TThread
  public
    procedure SetThreadName(const ThreadName: string);
  end;

procedure TThreadHelper.SetThreadName(const ThreadName: string);
begin
  TThread.NameThreadForDebugging(ThreadName, ThreadID);
end;
坦率地说,我不认为我会遇到这样的麻烦。拨打NameThreadForDebugging似乎就足够了。