C# 如何正确关闭日志线程
我有一个日志类,它包含一个线程安全队列、一个为该队列提供服务的C# 如何正确关闭日志线程,c#,.net,multithreading,application-shutdown,C#,.net,Multithreading,Application Shutdown,我有一个日志类,它包含一个线程安全队列、一个为该队列提供服务的线程、一些支持信号和一个bool: private ConcurrentQueue<LogEntry> _logQ; private Thread _thread; private volatile bool _running; private AutoResetEvent _logEntryWaitingSignal; private ManualResetEvent _shutdownSignal; 我有一段关机代码
线程、一些支持信号和一个bool
:
private ConcurrentQueue<LogEntry> _logQ;
private Thread _thread;
private volatile bool _running;
private AutoResetEvent _logEntryWaitingSignal;
private ManualResetEvent _shutdownSignal;
我有一段关机代码,它将\u running
布尔值设置为false
(一旦\u running
为false
,就不能再将队列添加到队列中),然后向线程发出唤醒信号,然后等待其处理所有等待条目并退出的信号:
_running = false;
try
{
_logEntryWaitingSignal.Set(); // Wakes the thread
// Wait for thread to complete
if(!_shutdownSignal.WaitOne(THREAD_SHUTDOWN_TIMEOUT_MILLISECONDS))
throw new Exception("Timed out waiting for thread to exit.");
}
catch(Exception ex)
{
...
}
我的问题是:我能否确保调用此代码,以便在任何可能的(有序的)进程终止情况下执行它
我已经尝试过从Dispose
执行它,并实现finalizer来调用Dispose
。只要调用Dispose
,例如从“我的应用程序”对话框的FormClosed
事件调用,它就可以正常工作。但是,我不相信终结器一定能以我想要的方式工作,因为即使拥有logger对象的线程退出,该线程在调用\u logEntryWaitingSignal.WaitOne()
时仍将保持活动状态,并且进程永远不会退出
当然,如果我把它变成后台线程,这个过程就会退出,但是如果我这么做了,我如何确保线程在写入一个条目中间不会被关闭?
为什么你首先要编写自己的记录器?有大量已经实施的解决方案。只要使用其中一个,如果你真的想创建自己的,看看他们是如何解决这个问题的。为什么不使用_thread.Join()而不是使用shutdownSignal?我会将其设置为后台线程,以避免在紧急情况下挂起退出。除此之外,我在你的代码中没有看到任何竞争条件。您可以在上设置\u running
等。最后,似乎日志存储系统不具有容错性——如果写入日志项中间有OS崩溃或断电会怎样?不管你做什么,在最坏的情况下,你都需要处理写了一半的日志条目。我把这个问题作为一个记录器来解决,以简化我的实际用例,它是数据收集系统的一部分。备份存储是一个SQLite数据库,因此部分完成的事务的一致性由该数据库处理。此线程的主要目的是将数据收集线程与将数据写入磁盘所需的时间差异隔离开来。它能够将多个条目批处理到单个事务中(如果它们可用),但如果没有任何条目等待,则立即完成事务。我关心的不是部分条目写入,而是等待的条目。
private void LoggingThread()
{
_running = true;
LogStore theLog = ...
// don't exit until all queued entries are written
while (_running || !_logQ.IsEmpty)
{
LogEntry entry;
int entryCount = 0;
while (_logQ.TryDequeue(out entry))
{
theLog.WriteEntry(entry);
}
_logEntryWaitingSignal.WaitOne();
}
_shutdownSignal.Set();
}
_running = false;
try
{
_logEntryWaitingSignal.Set(); // Wakes the thread
// Wait for thread to complete
if(!_shutdownSignal.WaitOne(THREAD_SHUTDOWN_TIMEOUT_MILLISECONDS))
throw new Exception("Timed out waiting for thread to exit.");
}
catch(Exception ex)
{
...
}