. net框架中的事件处理程序和多线程
本文关键字:程序 多线程 事件处理 框架 net | 更新日期: 2023-09-27 18:10:26
与FileSystemWatcher
类相关的FileSystemEventHandler
事件处理程序可以同时从不同的线程调用(彼此并行)吗?有任何保证吗?
一般来说,没有保证。
事件处理程序运行在它被调用的同一个线程上,但这并没有真正告诉你任何事情——你知道,它可以用ThreadPool.QueueUserWorkItem(() => EventHandler())
这样的东西调用。System.Timers.Timer
就是一个例子——定时器回调在一个线程池线程上调用,多个线程可以并行运行。
System.Windows.Forms.Timer
)只会在GUI线程上启动。然而,文档应该显式地指定事件处理程序具有某些特定的线程关联——这当然不是默认的假设。
FileSystemWatcher
尤其棘手。如果它设置了SynchronizingObject
,它将具有线程亲和性——将在同步对象上调用处理程序。例如,如果同步对象是Form
,则处理程序将始终在GUI线程上运行,并且永远不会并行运行。其他同步对象的行为可能不同(例如,您始终可以创建自己的同步对象,将委托发送到线程池)。请注意,调用是异步的——它执行BeginInvoke
,而不是Invoke
——因此,如果同步对象执行ThreadPool.QueueUserWorkItem
之类的操作,它很可能导致并行执行。
如果没有同步对象,则处理程序在接收通知的同一线程上运行。由于FileSystemWatcher
运行在IOCP上,可以很安全地假设它只是在回调期间借用线程池线程。然而,它也显式地围绕整个代码lock
s,包括事件处理程序调用-所以它不会并行运行
FileSystemWatcher
类的add
和remove
处理程序没有什么特别之处,因此—在大多数情况下—从哪个线程订阅方法完全无关紧要。如果你设置了FileSystemWatcher.SynchronizingObject
,委托将通过BeginInvoke
调用在该对象上调用;否则,它将在您的FileSystemWatcher
所在的线程中被调用。
委托的方法将在调用者的线程中依次调用,因此它们之间不存在同步问题。但是,如果在其他线程中,您使用订阅方法的公共资源,则必须像往常一样注意同步。