Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading Delphi中次线程上下文的检测_Multithreading_Delphi_Detect - Fatal编程技术网

Multithreading Delphi中次线程上下文的检测

Multithreading Delphi中次线程上下文的检测,multithreading,delphi,detect,Multithreading,Delphi,Detect,在Delphi 2009和Windows API中,是否有一种方法可以检测特定代码段是否在辅助线程的上下文中运行?在伪代码中,我想说: procedure DoSomething; begin if InvokedBySecondaryThread then DoIt_ThreadSafeWay else DoIt_RegularWay; end; 这是一个日志库,我编写并使用了多年,现在正试图适应一个可以从多个线程调用一个过程的情况。我的“常规方式”不是线程安全的。我

在Delphi 2009和Windows API中,是否有一种方法可以检测特定代码段是否在辅助线程的上下文中运行?在伪代码中,我想说:

procedure DoSomething;
begin
  if InvokedBySecondaryThread then
    DoIt_ThreadSafeWay
  else
    DoIt_RegularWay;
end;
这是一个日志库,我编写并使用了多年,现在正试图适应一个可以从多个线程调用一个过程的情况。我的“常规方式”不是线程安全的。我知道如何使其线程安全,但我只想在实际需要时使用线程安全方法

说明(非必读资料:-)

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

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

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

@列文:目前,日志逻辑是这样的,有些简化

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

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 );
检查singleton dispatcher对象是否已初始化;(b) 创建TLogMessagePacket对象的实例(用于消息文本、时间戳等的容器),最后(c)执行SendMessage或PostMessage以将“数据包”发送给dispatcher(它有一个窗口句柄来接收它)

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

当调度器接收到消息“packet”时,它依次将其交给每个接收者,然后释放它


因此,我可能固定在上述思维方式中,这就是为什么当您说将dispatcher对象传递给日志库的代码应该根据线程上下文选择一个时,我不太明白您的想法。dispatcher实际上是库的主要引擎,一次只存在一个

应您的要求,我添加了一些示例代码来说明我的意思

  if GetCurrentThreadID = MainThreadID then begin
// in main thread
  end
  else begin
// in secondary thread
  end; 
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的测试更加容易


这样看:你将如何编写一个单元测试来验证消息确实被发布了?

+ 1,但是OP应该考虑将这样的结构从日志库中删除。在我看来,应该为库提供一个发送消息的对象。将dispatcher对象传递到日志库的代码应该根据线程上下文选择一个。@Lieven:我不确定我是否正确地想象了您的建议,但我对更好的解决方案感兴趣。我将在OP中添加一个关于我当前日志记录流的快速解释。在(尝试)进行TDD时,我可能会因为将天平过度倾斜到“我将如何测试这个,让我们使用DI”而感到内疚,并且忘记了KISS。您的编辑清楚地表明,使用一(两)个单独的对象来执行实际的Post/SendMessage几乎没有任何附加值。我认为您没有抓住要点。如果在多线程应用程序的主线程中调用例程,并且选择运行非线程安全的代码,则可能会产生冲突(以非线程安全的方式)。我想你想知道的是调用例程的应用程序是否是多线程的。