. net框架中的事件处理程序和多线程

本文关键字:程序 多线程 事件处理 框架 net | 更新日期: 2023-09-27 18:10:26

FileSystemWatcher类相关的FileSystemEventHandler事件处理程序可以同时从不同的线程调用(彼此并行)吗?有任何保证吗?

. net框架中的事件处理程序和多线程

一般来说,没有保证。

事件处理程序运行在它被调用的同一个线程上,但这并没有真正告诉你任何事情——你知道,它可以用ThreadPool.QueueUserWorkItem(() => EventHandler())这样的东西调用。System.Timers.Timer就是一个例子——定时器回调在一个线程池线程上调用,多个线程可以并行运行。

主要的例外是在一些同步上下文中使用的事件——例如,Windows窗体中的GUI事件(包括System.Windows.Forms.Timer)只会在GUI线程上启动。然而,文档应该显式地指定事件处理程序具有某些特定的线程关联——这当然不是默认的假设。

FileSystemWatcher尤其棘手。如果它设置了SynchronizingObject,它将具有线程亲和性——将在同步对象上调用处理程序。例如,如果同步对象是Form,则处理程序将始终在GUI线程上运行,并且永远不会并行运行。其他同步对象的行为可能不同(例如,您始终可以创建自己的同步对象,将委托发送到线程池)。请注意,调用是异步的——它执行BeginInvoke,而不是Invoke——因此,如果同步对象执行ThreadPool.QueueUserWorkItem之类的操作,它很可能导致并行执行。

如果没有同步对象,则处理程序在接收通知的同一线程上运行。由于FileSystemWatcher运行在IOCP上,可以很安全地假设它只是在回调期间借用线程池线程。然而,它也显式地围绕整个代码lock s,包括事件处理程序调用-所以它不会并行运行

FileSystemWatcher类的addremove处理程序没有什么特别之处,因此—在大多数情况下—从哪个线程订阅方法完全无关紧要。如果你设置了FileSystemWatcher.SynchronizingObject,委托将通过BeginInvoke调用在该对象上调用;否则,它将在您的FileSystemWatcher所在的线程中被调用。

委托的方法将在调用者的线程中依次调用,因此它们之间不存在同步问题。但是,如果在其他线程中,您使用订阅方法的公共资源,则必须像往常一样注意同步。