Skip to main content
 首页 » 编程设计

c#之控制台锁定在 TraceSource 方法中的线程

2024年05月10日39sharpest

我遇到了一个情况,不知道能不能解决。

我已经开始向我的多线程服务添加 TraceSource 和跟踪语句,但我在处理代码中的跟踪方法的线程中遇到了锁。这会导致整个应用挂起。

我的服务配置为在控制台窗口中运行以进行调试。我知道这与问题有关,因为我也在写信给 ConsoleTraceListener。

这种锁定似乎发生在外部代码和对 Console.ReadKey() 的内部调用之间。作为代码和配置的示例,我的应用程序可能会在异步方法中进行如下调用:

class MyService : ServiceBase 
{ 
    static TraceSource trace = new TraceSource("mysource"); 
 
    void asyncMethod1() 
    { 
        trace.TraceInformation("Some useful information."); 
    } 
 
    void asyncMethod2() 
    { 
        trace.TraceInformation("Some other useful information."); 
    } 
 
    /// other members and methods ... 
} 

TraceSource 在 app.config 文件中定义为

<?xml version="1.0" encoding="utf-8"?> 
<configuration> 
  <startup> 
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/> 
  </startup> 
  <system.diagnostics> 
    <trace autoflush="true" indentsize="4" useGlobalLock="true" /> 
    <sources> 
      <source name="mysource" switchName="TraceSwitch" switchType="System.Diagnostics.SourceSwitch"> 
        <listeners> 
          <add name="console" /> 
          <add name="eventlog" /> 
          <add name="logfile" /> 
        </listeners> 
      </source> 
    </sources> 
    <sharedListeners> 
      <add name="console" type="System.Diagnostics.ConsoleTraceListener" initializeData="false" /> 
      <add name="eventlog" type="System.Diagnostics.EventLogTraceListener" initializeData="EventSource"> 
        <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error"/> 
      </add> 
      <add name="logfile" type="System.Diagnostics.TextWriterTraceListener" initializeData="logfiles\errors.log"> 
        <filter type="System.Diagnostics.EventTypeFilter" initializeData="Error"/> 
      </add> 
    </sharedListeners> 
    <switches> 
      <add name="TraceSwitch" value="Information" /> 
    </switches> 
  </system.diagnostics> 
</configuration> 

重现问题

应用启动后,Program.Main(args[]) 中的代码等待 Console.ReadKey() 停止应用。

static int Main(string[] args) 
{ 
    /// ... 
 
    MyService service = new MyService(); 
    service.StartService(); 
 
    Console.WriteLine("Press any key to exit application."); 
    Console.ReadKey(true); 
 
    ///... 
} 

当我在控制台中运行该服务并使用快速编辑模式在控制台窗口中的任意位置单击或选择鼠标时,TraceSource 方法调用会锁定应用程序的其余部分,直到我点击键也可以停止应用程序。

有什么方法可以防止此控制台线程锁定其他线程?还是我误解了这里发生的事情?


在我单击控制台窗口重现问题后,调用堆栈可能如下所示:

线程 1

[Managed to Native Transition]   
System.IO.__ConsoleStream.WriteFileNative 
System.IO.__ConsoleStream.Write 
System.IO.StreamWriter.Flush 
System.IO.StreamWriter.Write 
System.IO.TextWriter.SyncTextWriter.Write 
System.Diagnostics.TextWriterTraceListener.Write 
System.Diagnostics.TraceListener.WriteHeader 
System.Diagnostics.TraceListener.TraceEvent 
System.Diagnostics.TraceSource.TraceEvent 
System.Diagnostics.TraceSource.TraceInformation 
myservice.MyService.asyncMethod1 Line 202   C# 

线程 2

System.Threading.Monitor.Enter 
System.Diagnostics.TraceSource.TraceEvent 
System.Diagnostics.TraceSource.TraceInformation 
myservice.MyService.asyncMethod2 Line 134   C# 

请您参考如下方法:

运算符(operator):

When I run the service in console, and click with the mouse anywhere in the console window, the TraceSource method calls lock up the rest of the application, until I hit a key which also stops the application.

Would you try turning on quickedit in your console, and use the mouse to highlight some characters?

根据我们在上述问题下方的对话,它似乎挂起的原因是在 QuickEdit 模式/突出显示文本期间,所有线程的控制台输出都被挂起。这已在 Visual Studio 调试器中得到确认。

要继续执行,请按 Esc 或单击鼠标右键。

运算符(operator):

I was wondering do you know if there was a way to prevent this behaviour

是的,Jim Mishel 写道:

If you want to disable quick edit mode, you need to call GetConsoleMode to get the current mode. Then clear the bit that enables quick edit

您可以找到更多关于 Jim's answer here 的信息.