记录和同步 [英] Logging and Synchronization
问题描述
type
ILogger = Interface(IInterface)
程序Log(const LogString:String; LogLevel:TLogLevel);
过程SetLoggingLevel(LogLevel:TLogLevel);
结束
type
TGUILogger = class(TInterfacedObject,ILogger)
public
构造函数Create(Target:TStrings);
procedure Log(const LogString:String; LogLevel:TLogLevel);
过程SetLoggingLevel(LogLevel:TLogLevel);
private
procedure PerformLogging;
结束
程序TGUILogger.Log(const LogString:String; LogLevel:TLogLevel);
begin
TMonitor.Enter(Self);
try
FLogString:= GetDateTimeString +''+ LogString;
TThread.Synchronize(TThread.CurrentThread,PerformLogging);
finally
TMonitor.Exit(Self);
结束
结束
程序TGUILogger.PerformLogging;
begin
FTarget.Add(FLogString);
结束
日志记录工作,但应用程序未正确关闭。它似乎挂在班级单位。堆栈跟踪:
System.Halt0,System.FinalizeUnits,Classes.Finalization,Classes.FreeExternalThreads,
System.TObject.Free,Classes.TThread.Destroy ,Classes.TThread.RemoveQueuedEvents
我在这里做错什么?
编辑:我刚刚发现以下提示Delphi帮助TThread.StaticSynchronize
警告:不要在主线程内调用StaticSynchronize。这可能导致
无限循环。
这可能是我的问题,因为某些日志记录请求来自主线程。如何解决这个问题?
如果没有找到更简单的方法,可以尝试这样做:
在程序初始化时,(从主线程),您的记录子系统调用Windows API函数GetCurrentThreadID并将结果存储在变量中。 (编辑:系统单元中的MainThreadID变量,在启动时为您自动初始化)谢谢,mghie。)当记录请求进入后,再次调用GetCurrentThreadID,只有当来自不同的线程才能同步。
还有其他不涉及Windows API的技巧,但最终会变得更加复杂,特别是如果您有一大堆不同的自定义TThread后代。基本原则是一样的,但是:在决定是否调用StaticSynchronize之前,验证是否处于主线程。
I have just written my own logging framework (very lightweight, no need for a big logging framework). It consists of an interface ILogger and a number of classes implementing that interface. The one I have a question about is TGUILogger which takes a TStrings as the logging target and synchronizes the logging with the main thread so that the Items member of a listbox can be used as the target.
type
ILogger = Interface (IInterface)
procedure Log (const LogString : String; LogLevel : TLogLevel);
procedure SetLoggingLevel (LogLevel : TLogLevel);
end;
type
TGUILogger = class (TInterfacedObject, ILogger)
public
constructor Create (Target : TStrings);
procedure Log (const LogString : String; LogLevel : TLogLevel);
procedure SetLoggingLevel (LogLevel : TLogLevel);
private
procedure PerformLogging;
end;
procedure TGUILogger.Log (const LogString : String; LogLevel : TLogLevel);
begin
TMonitor.Enter (Self);
try
FLogString := GetDateTimeString + ' ' + LogString;
TThread.Synchronize (TThread.CurrentThread, PerformLogging);
finally
TMonitor.Exit (Self);
end;
end;
procedure TGUILogger.PerformLogging;
begin
FTarget.Add (FLogString);
end;
The logging works, but the application does not close properly. It seems to hang in the Classes unit. The stack trace:
System.Halt0, System.FinalizeUnits, Classes.Finalization, Classes.FreeExternalThreads, System.TObject.Free, Classes.TThread.Destroy, Classes.TThread.RemoveQueuedEvents
What am I doing wrong here?
EDIT: I just found the following hint in the Delphi help for TThread.StaticSynchronize
Warning: Do not call StaticSynchronize from within the main thread. This can cause
an infinite loop.
This could be exactly my problem since some logging request come from the main thread. How can I solve this?
If you don't find any simpler way, you could try doing this:
At program initialization, (from the main thread,) have your logging subsystem call the Windows API function GetCurrentThreadID and store the result in a variable. (EDIT: the MainThreadID variable in the System unit, gets initialized this way automatically for you at startup. Thanks, mghie.) When a logging request comes in after that, call GetCurrentThreadID again, and only synchronize if it's coming from a different thread.
There are other tricks that don't involve the Windows API, but they end up being more complicated, especially if you have a bunch of different custom TThread descendants. The basic principle is the same, though: Verify whether or not you're in the main thread before you decide whether or not to call StaticSynchronize.
这篇关于记录和同步的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!