如果应用程序在处理程序内写入先前条目时将新条目写入事件日志,会发生什么情况?

What happens if a new Entry is written to the Event Log while the application is inside the handler for a previous entry being written?

我的应用程序需要审查所有新的应用程序事件日志条目。

private void eventLog_Application_EntryWritten(object sender, EntryWrittenEventArgs e)
{
    // Process e.Entry    
}

我想知道如果在处理前一个条目时将另一个条目写入事件日志会发生什么情况?


EventLog.EntryWritten Event 的文档提供了一个使用线程处理条目写入事件的示例(这就是我问这个问题的原因)。

在此示例中,他们使用 System.Threading 并在 AutoResetEvent class 上调用 WaitOne()Set() 方法,但我不确定是否准确此代码旨在实现什么。

文档指出 - WaitOne() "blocks the current thread until the current WaitHandle receives a signal" 和 Set() "sets the state of the event to signaled, allowing one or more waiting threads to proceed"。我不确定此示例的 线程部分 旨在演示什么,以及这与它如何(或是否)需要在实践中应用有何关系。

似乎 WaitOne() 在写入条目后立即阻塞线程,直到它被处理,然后将其设置为有信号(使用 Set()),然后才允许线程继续。这是应用程序的唯一线程吗?

最重要的是,当我的应用程序负责写入需要从事件日志中读取的事件时,应该如何这个原则适用吗? (如果确实需要申请的话。)

如果在应用程序位于处理程序中时写入新的 Entry 会发生什么情况?

根据 https://msdn.microsoft.com/en-us/library/0680sfkd.aspx,事件日志组件不是线程安全的,该代码用于防止同时交互中的意外行为。

If multiple threads are executing these lines simultaneously, if is possible for one thread to change the EventLog.Source Property of the event log, and for another thread to write a message, after that property had been changed.

该示例并不能真正帮助解释 AutoResetEvent 在多线程场景中的工作方式,因此我将尝试解释我对它的工作方式的理解。

AutoResetEvent signal 静态变量被实例化为一个新的 AutoResetEvent,其信号状态设置为 false,或 "non-signaled",这意味着调用 signal.WaitOne() 将导致调用 WaitOne 等待,直到 signal 变量通过调用 signal.Set() 方法变为 "set"。

我找到了 AutoResetEvent 的解释,该解释以可理解的现实世界术语对其进行了很好的描述,其中还包括下面这个出色的示例。 http://www.albahari.com/threading/part2.aspx#_AutoResetEvent

AutoResetEvent

An AutoResetEvent is like a ticket turnstile: inserting a ticket lets exactly one person through. The “auto” in the class’s name refers to the fact that an open turnstile automatically closes or “resets” after someone steps through. A thread waits, or blocks, at the turnstile by calling WaitOne (wait at this “one” turnstile until it opens), and a ticket is inserted by calling the Set method. If a number of threads call WaitOne, a queue builds up behind the turnstile. (As with locks, the fairness of the queue can sometimes be violated due to nuances in the operating system). A ticket can come from any thread; in other words, any (unblocked) thread with access to the AutoResetEvent object can call Set on it to release one blocked thread.

class BasicWaitHandle
{
  static EventWaitHandle _waitHandle = new AutoResetEvent (false);

  static void Main()
  {
    new Thread (Waiter).Start();
    Thread.Sleep (1000);                  // Pause for a second...
    _waitHandle.Set();                    // Wake up the Waiter.
  }

  static void Waiter()
  {
    Console.WriteLine ("Waiting...");
    _waitHandle.WaitOne();                // Wait for notification
    Console.WriteLine ("Notified");
  }
}

没有什么戏剧性的事情发生,它被框架序列化了。触发EventWritten事件的底层winapi函数是NotifyChangeEventLog(). The .NET Framework uses the threadpool to watch for the event to get signaled with ThreadPool.RegisterWaitForSingleObject(). You can see it being used here.

这就是 MSDN 示例使用 ARE (AutoResetEvent) 的原因。该线程池线程上的事件处理程序 运行s,具体发生时间是不可预测的。该示例使用控制台模式应用程序,否则它会立即终止。对于 ARE,它会显示一个通知并退出。当然实际上并没有那么有用,我个人只是在示例中使用了 Console.ReadLine(),所以它只会保持 运行ning 并继续显示信息,直到您按下 Enter 键。

如果您使用服务或 GUI 应用程序,则不需要它,这些应用程序会 运行 很长时间,直到用户明确关闭它。请注意 EventLog.SynchronizingObject 属性,这使得不必在 Winforms 应用程序中处理线程池线程变得容易。