如何让后台记录器类在应用程序退出时完成日志记录。(C#多线程)

如何让后台记录器类在应用程序退出时完成日志记录。(C#多线程),c#,.net,multithreading,logging,C#,.net,Multithreading,Logging,我是C#编程新手,为了学习,我想制作一个在低优先级后台线程上运行的异步应用程序记录器。我已经编写了一个logger类,它作为应用程序中任何其他类的接口来创建新的日志条目。然后,该记录器将其简单地发送给日志调度器,然后将其推送到BlockingCollection,循环从中不断尝试从后台线程上获取日志并写入日志文件 但是,我遇到的问题是,如果应用程序在退出之前请求日志条目,则永远不会写入日志。LogDispatcher的Dispose方法也不会被调用,因为该方法中的退出日志从未被写入。我不知道如何

我是C#编程新手,为了学习,我想制作一个在低优先级后台线程上运行的异步应用程序记录器。我已经编写了一个logger类,它作为应用程序中任何其他类的接口来创建新的日志条目。然后,该记录器将其简单地发送给日志调度器,然后将其推送到BlockingCollection,循环从中不断尝试从后台线程上获取日志并写入日志文件

但是,我遇到的问题是,如果应用程序在退出之前请求日志条目,则永远不会写入日志。LogDispatcher的Dispose方法也不会被调用,因为该方法中的退出日志从未被写入。我不知道如何使后台线程在终止之前完成整个阻塞集合,然后在父应用程序线程终止时调用dispose方法。这是代码

 public sealed class Logger : ILogger
 {
    // Fully lazy implementation for 
    // 1) learning purposes and
    // 2) in case log disabling is a feature to be added in the future
    private static readonly Lazy<Logger> L = new Lazy<Logger>(() => new Logger());

    public static Logger Instance
    {
        get
        {
            return L.Value;
        }
    }

    private double entryNumber = 0;
    private int verbosity { get; set; }`private Logger()
    {
        this.verbosity = 3;
        LogDispatcher.Instance.pushNewLog(new Log(
            Log.LogType.Debug,
            entryNumber++,
            "LOG -- LogFile created with verbosity " + this.verbosity,
            DateTime.Now.ToString("yyyy - mm - dd hh: mm:ss.fff")));
    }

    public void debug(string message)
    {
        if (this.verbosity > 2)
        {
            LogDispatcher.Instance.pushNewLog(new Log(
                Log.LogType.Debug,
                entryNumber++,
                message,
                DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"
            )));
        }
    }

    public void warning(string warning)
    {
        if (this.verbosity > 1)
        {
            LogDispatcher.Instance.pushNewLog(new Log(
                Log.LogType.Warning,
                entryNumber++,
                warning,
                DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"
            )));
        }
    }

    public void exception(string message, Exception e)
    {
        LogDispatcher.Instance.pushNewLog(new Log(
            Log.LogType.Exception,
            (entryNumber++),
            message,
            DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff"),
            Thread.CurrentThread.ManagedThreadId,
            e
        ));
    }
公共密封类记录器:ILogger
{
//完全惰性实现
//1)学习目的和方法
//2)如果日志禁用是将来添加的功能
private static readonly Lazy L=new Lazy(()=>new Logger());
公共静态记录器实例
{
得到
{
返回L.值;
}
}
专用双入口编号=0;
private int详细信息{get;set;}`private Logger()
{
这个。冗长=3;
LogDispatcher.Instance.pushNewLog(新日志(
Log.LogType.Debug,
entryNumber++,
“LOG—使用verbosity创建的日志文件”+this.verbosity,
DateTime.Now.ToString(“yyyy-mm-dd hh:mm:ss.fff”);
}
公共void调试(字符串消息)
{
如果(this.verbosity>2)
{
LogDispatcher.Instance.pushNewLog(新日志(
Log.LogType.Debug,
entryNumber++,
消息
DateTime.Now.ToString(“yyyy-mm-dd hh:mm:ss.fff”
)));
}
}
公共无效警告(字符串警告)
{
如果(this.verbosity>1)
{
LogDispatcher.Instance.pushNewLog(新日志(
Log.LogType.Warning,
entryNumber++,
警告
DateTime.Now.ToString(“yyyy-mm-dd hh:mm:ss.fff”
)));
}
}
公共无效异常(字符串消息,异常e)
{
LogDispatcher.Instance.pushNewLog(新日志(
Log.LogType.Exception,
(entryNumber++),
消息
DateTime.Now.ToString(“yyyy-mm-dd hh:mm:ss.fff”),
Thread.CurrentThread.ManagedThreadId,
E
));
}
调度器的代码如下所示

internal class LogDispatcher : IDisposable
{
    private static readonly Lazy<LogDispatcher> LD = new Lazy<LogDispatcher>(() => new LogDispatcher());

    private readonly StreamWriter LogFile;

    private readonly BlockingCollection<Log> logQueue;

    private Thread loggingThread;

    private bool terminate = false;

    public static LogDispatcher Instance
    {
        get
        {
            return LD.Value;
        }
    }private LogDispatcher()
    {
        // initialize the log folder
        string logPath = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) + "\\NETLogger";
        {
            try
            {
                Directory.CreateDirectory(logPath);
            }
            catch (Exception e)
            {
                Console.WriteLine("An error occured while making the logfile.");
                Console.WriteLine(e.ToString());
            }
        }

        // now make logfile
        try
        {
            this.LogFile = File.CreateText(logPath + "\\LogFile.txt");
            this.LogFile.AutoFlush = true;
        }
        catch (Exception e)
        {
            Console.WriteLine("An error occured while opening LogFile.txt");
            Console.WriteLine(e.ToString());
        }

        // make the blocking collection that stores all queued logs
        this.logQueue = new BlockingCollection<Log>();

        // initialize writer loggingThread to run in the background
        this.loggingThread = new Thread(new ThreadStart(logWriter));
        this.loggingThread.IsBackground = true;
        this.loggingThread.Start();
    }

    public void logWriter()
    {
        Log writingLog = new Log();
        while (!terminate && logQueue.Count != 0)
        {
            if (this.logQueue.TryTake(out writingLog, -1))
            {
                switch(writingLog.lType)
                {
                    case (Log.LogType.Debug) :
                        LogFile.WriteLine(writingLog.entryNumber + " -- DEBUG -- " + writingLog.timeStamp);
                        LogFile.WriteLine("\t" + writingLog.message);
                        break;

                    case (Log.LogType.Warning) :
                        LogFile.WriteLine(writingLog.entryNumber + " -- WARNING -- " + writingLog.timeStamp);
                        LogFile.WriteLine("\t" + writingLog.message);
                        break;

                    case (Log.LogType.Exception) :
                        LogFile.WriteLine(writingLog.entryNumber + " -- EXCEPTION -- " + writingLog.timeStamp);
                        LogFile.WriteLine("\t ============== EXCEPTION INFORMATION FOLLOWS ============== ");
                        LogFile.WriteLine("\t Log Message : " + writingLog.message);
                        LogFile.WriteLine("\t Exception Message: " + writingLog.e.Message);
                        LogFile.WriteLine("\t Exception Thread :" + writingLog.threadId);
                        LogFile.WriteLine("\t Source: " + writingLog.e.ToString());
                        LogFile.WriteLine("\t=============== END EXCEPTION INFORMATION ================== ");
                        break;
                }
            }
        }
    }

   public void pushNewLog(Log log)
    {
        logQueue.Add(log);
    }

    public void Dispose()
    {
        this.logQueue.Add(new Log(
            Log.LogType.Debug,
            -1,
            "Terminating All Logging Procedures",
            DateTime.Now.ToString("yyyy-mm-dd hh:mm:ss.fff")));
        this.logQueue.CompleteAdding();
        this.terminate = true;
        this.loggingThread.Join();
    }

    ~LogDispatcher()
    {
        this.Dispose();
    }
内部类日志调度程序:IDisposable
{
private static readonly Lazy LD=new Lazy(()=>new LogDispatcher());
私有只读StreamWriter日志文件;
私有只读阻止收集日志队列;
私有线程记录线程;
私有布尔终止=假;
公共静态LogDispatcher实例
{
得到
{
返回LD.Value;
}
}专用日志调度器()
{
//初始化日志文件夹
字符串logPath=Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData)+“\\NETLogger”;
{
尝试
{
CreateDirectory(logPath);
}
捕获(例外e)
{
WriteLine(“创建日志文件时出错。”);
Console.WriteLine(如ToString());
}
}
//现在制作日志文件
尝试
{
this.LogFile=File.CreateText(logPath+“\\LogFile.txt”);
this.LogFile.AutoFlush=true;
}
捕获(例外e)
{
WriteLine(“打开LogFile.txt时出错”);
Console.WriteLine(如ToString());
}
//创建存储所有排队日志的阻塞集合
this.logQueue=new BlockingCollection();
//初始化writer loggingThread以在后台运行
this.loggingThread=新线程(新线程开始(logWriter));
this.loggingThread.IsBackground=true;
this.loggingThread.Start();
}
公共日志编写器()
{
日志写入日志=新日志();
而(!terminate&&logQueue.Count!=0)
{
if(this.logQueue.TryTake(out writingLog,-1))
{
开关(writingLog.lType)
{
案例(Log.LogType.Debug):
LogFile.WriteLine(writingLog.entryNumber+--DEBUG--“+writingLog.timeStamp);
LogFile.WriteLine(“\t”+writingLog.message);
打破
案例(Log.LogType.Warning):
LogFile.WriteLine(writingLog.entryNumber+“--警告--”+writingLog.timeStamp);
LogFile.WriteLine(“\t”+writingLog.message);
打破
案例(Log.LogType.Exception):
LogFile.WriteLine(writingLog.entryNumber+“--EXCEPTION--”+writingLog.timeStamp);
LogFile.WriteLine(“\t======================================================================”);
LogFile.WriteLine(“\t日志消息:“+writingLog.Message”);
LogFile.WriteLine(“\t异常消息:“+writingLog.e.Message”);
LogFile.WriteLine(“\t异常线程:”+writingLog.threadId);
LogFile.WriteLine(“\t源:+writingLog.e.ToString());
LogFile.WriteLine(“\t======================================================================”);
打破
Task task1 = Task.Factory.StartNew(() => DoSomething());
Task task2 = Task.Factory.StartNew(() => DoSomethingElse());
Task.WaitAll(task1, task2);
Console.WriteLine("All threads complete");
public class ComplexResourceHolder : IDisposable
{

    private IntPtr buffer; // unmanaged memory buffer
    private SafeHandle resource; // disposable handle to a resource

    public ComplexResourceHolder()
    {
        this.buffer = ... // allocates memory
        this.resource = ... // allocates the resource
    }

    // disposing will be false when it is called from the finalize. 
    // I remember this by telling myself: "finalize has 'f' in it 
    // and false has 'f' in it so disposing is false when called by finalizer".
    protected virtual void Dispose(bool disposing)
    {
        ReleaseBuffer(buffer); // release unmanaged memory
        if (disposing)
        { // release other disposable objects
            if (resource != null) resource.Dispose();
        }
    }

    ~ComplexResourceHolder()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }
}