在Delphi中检测辅助线程上下文

时间:2010-11-04 14:36:50

标签: multithreading delphi detect

在Delphi 2009和Windows API中,有没有办法检测某个特定代码段是否在辅助线程的上下文中运行?在伪代码中,我希望能够说:

procedure DoSomething;
begin
  if InvokedBySecondaryThread then
    DoIt_ThreadSafeWay
  else
    DoIt_RegularWay;
end;

这是我编写并已使用多年的日志库,现在我正在尝试适应可以从多个线程调用一个过程的情况。我的“常规方式”不是线程安全的。我知道如何使它线程安全,但我只想在实际需要时使用线程安全方法。

解释(不是必读的: - )

归结为使用SendMessage和PostMessage将记录的消息分派给多个接收器(例如日志文件,控制台或VCL控件)之间的选择。使用PostMessage意味着在长时间阻塞操作正在进行时将不会收到消息,这有点违背了记录的目的,尤其是。用来表示进度。我想我可以用一个关键部分来保护SendMessage调用,但我再次希望只有在真正需要的时候才能这样做。

我知道system.pas中的全局变量IsMultiThread,但这只会告诉我应用程序已经启动了辅助线程。这些可能是由第三方库创建的线程,因此它们永远不会访问“我的”代码,因此它们的存在不会影响我的日志逻辑。

我真的希望我可以使用相同的低级库代码,无论它是从一个还是多个线程调用。例如,从内部辅助线程调用修改的线程安全日志记录过程很容易,但是这会复制很多代码,而且我仍然必须记住以便始终做正确的事情。

@Lieven:目前,日志逻辑就像这样,有点简化

我希望日志记录尽可能轻松,只需最少的设置代码,不用担心管理对象的生命周期,因此库只暴露了一些重载的帮助程序,例如

procedure Log( const msgText : string; level : TLogLevel = lvNotice ); overload;
procedure Log( const msgText : string; Args : array of const; level : TLogLevel = lvNotice ); overload;
etc, including specialized routines that log a StringList, a boolean, an Exception and so on

几乎所有其他事情都发生在单位的实施中。所有帮助程序最终都会调用

procedure _LogPostMessage( const msgText : string; level : TLogLevel );

其中(a)检查单例调度程序对象是否已初始化; (b)创建一个TLogMessagePacket对象的实例(消息文本的容器,时间戳等),最后(c)执行SendMessage或PostMessage将“数据包”发送给调度程序(它有一个窗口句柄来接收它) )。

然后有一组来自抽象TLogReceiver类的类。一个这样的类接收记录的消息并将它们写入文件,另一个更新TMemo等。我实例化我想在项目中使用的具体接收器,并将其注册到调度程序,调度程序从那时起拥有它们。

当调度员收到消息“数据包”时,它依次将其交给每个接收者,然后释放它。

所以我可能已经修改了上面的思维方式,这就是为什么当你说代码将调度程序对象交给日志库时应该根据线程上下文选择一个时,我不太明白你的想法>。调度程序实际上是库的主要引擎,一次只存在一个。

2 个答案:

答案 0 :(得分:14)

  if GetCurrentThreadID = MainThreadID then begin
// in main thread
  end
  else begin
// in secondary thread
  end; 

答案 1 :(得分:0)

根据您的要求,我添加了一些示例代码来展示我的意思。

interface
  procedure Log( const msgText : string; level : TLogLevel = lvNotice; dispatcher: IDispatcher = nil); overload;
...

implementation    

  procedure Log( const msgText : string; level : TLogLevel = lvNotice; dispatcher: IDispatcher = nil); overload;
  var
    dp: IDispatcher;
  begin
    if dispatcher = nil then dp := CreateDefaultDispatcher
    else dp := dispatcher;

    dp.msgText := msgText;
    dp.level := level;
    ...
  end;

procedure _LogPostMessage( dispatcher: IDispatcher );
begin
  dispatcher.LogPostMessage            
end;

现在这会给你带来什么?

除了已经指出的增加的复杂性之外,还不是很多,但它使得更容易测试_LogPostMessage。

以这种方式看待它:你如何编写一个单元测试来验证确实发布了一条消息?