最近我开发了一个高并发事件驱动框架(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的亲切帮助。为了帮助其他读者更好地理解我的问题,这个问题已被重新改写。
我的代码出了什么问题?
NameThreadForDebugging
方法实际上是一种静态方法。第二个参数ThreadId
是可选的,默认情况下它等于当前的线程ID。如果我没有清楚地给出ThreadId
,我可能很可能命名当前的线程,而不是我真正想要命名的线程。
解决方案是什么?
在任意位置拨打MyThread.NameThreadForDebugging('a_name', MyThread.ThreadId);
或在NameThreadForDebugging('a_name');
开头致电TMyThread.Execute
。
为什么如此困惑才能使事情正确?
我不明白,为什么不在没有第二个ThreadId
的情况下提供非静态版本。如果有这样的非静态版本,我就不会犯这个错误。
答案 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
似乎就足够了。