【问题标题】:How do I detect when the main thread has finished execution如何检测主线程何时完成执行
【发布时间】:2019-12-28 01:40:00
【问题描述】:

我有一个在它自己的线程上运行的记录器,以防止减慢主线程。使其成为单线程会更容易,但我有很多慢代码(写入多个文件,从堆栈跟踪获取信息)等等。执行顺序为:

主线程

Logger.Log("foo"); //Creates stack trace for me
//Message and stack trace get added to queue

记录器线程(在 while 循环中)

//Sees queued message
//Formats it (slow)
//Writes it to (one or more) streams and the console (*very* slow)

我的问题是,如果我将记录器线程设为前台线程,它会阻止应用程序在 Main 完成后关闭,但如果我将其设为后台,它通常会被切断并且无法写入大部分内容最近记录的消息。有没有办法让一个函数在应用程序退出之前运行“刷新”队列,同时保持线程背景? (我不能总是假设使用我的库的人会在应用退出之前调用一个函数,在某些情况下(cough Unity cough)他们真的没有很多控制)

【问题讨论】:

  • 您可以考虑使用经过验证的日志库。我知道 Serilog 有一个 Flush() 方法就是为了这个目的。日志记录不是小事,除非你有令人信服的理由,否则不要写它。
  • 我自己写的主要原因是因为我需要能够轻松自定义它,例如写入多个文件,更改消息格式等)。
  • 好的,所以是 Serilog、NLog 或 Log4Net。您可以使用格式化写入文件、App Insights、http 端点、控制台、电子邮件等。 github.com/serilog/serilog/wiki/Provided-Sinks
  • 太棒了!我没有意识到它们是如此可定制的。我想我会使用 Serilog。谢谢。
  • 回到问题:“我会使用类似 IDisposable 的东西来清理 Logger 线程并等待它完成。(如设置 WaitEvent)

标签: c# multithreading logging


【解决方案1】:

您需要在线程之间进行某种同步。与其使用您自己的线程,不如考虑使用任务,它们仍然作为线程运行。在主线程内部,您可以等待其他任务完成,甚至可以使用 CancellationTokens 向它们发出信号。

当您的“其他记录器线程”获得取消时,它可以刷新并退出它的日志。

这是一个使用 Serilog 和 Console Sink 的演示,您可能想要使用两个不同的 ILogger 实例。

    static async Task OtherLoggerAsync(CancellationToken ct)
    {
        await Task.Yield();

        // This method is now running on it's own thread
        while (true)
        {
            Log.Information("Other logger logged on thread");
            await Task.Delay(750); // Mimic some work

            if (ct.IsCancellationRequested)
            {
                Log.Logger.Information("OtherLoggerAsync() exiting");
                break;
            }
        }
    }

    static async Task Main(string[] args)
    {
        Log.Logger = new LoggerConfiguration()
            .WriteTo.Console()
            .CreateLogger();

        using (CancellationTokenSource cts = new CancellationTokenSource())
        {
            // Create the cancellation token
            var ct = cts.Token;

            // Start the other logger with the cancellation token
            var t = OtherLoggerAsync(ct);

            // Still in the main thread
            for (var i = 0; i < 10; i++)
            {
                Log.Logger.Information("Main thread logged");
                await Task.Delay(1000); // Mimic some work
            }

            // Main thread has finished.  We want to stop the OtherLogger Thread
            // if it has finsihed or not.

            // signal the cancellation
            cts.Cancel();

            // wait for it to finish
            Task.WaitAll(t);

            Log.Logger.Information("Main thread exiting");
            Log.CloseAndFlush();
        }
    }

【讨论】:

  • 这个方法现在在它自己的线程上运行
猜你喜欢
  • 1970-01-01
  • 2011-02-15
  • 2021-08-10
  • 2015-03-25
  • 1970-01-01
  • 2016-04-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多