【发布时间】:2013-02-03 00:40:48
【问题描述】:
当事件触发时,它们使用线程池中的线程。因此,如果您有一堆事件的触发速度比它们返回的速度快,那么您就会耗尽线程池。因此,只要您有一个事件处理程序方法,该方法没有任何其他控件来限制线程进入的速率,并且不能保证快速返回,并且您不会在其中煞费苦心地实现 100% 线程安全代码方法,最好实现一些线程控制。显而易见的简单事情是在事件处理方法中使用 lock(),但如果这样做,第一个线程之后的所有线程将阻塞在队列中,等待进入锁定区域,从线程池中占用所有线程。最好检测另一个线程在这个方法中,然后快速中止。
问题是:我有一种方法可以检测到另一个已经在运行的线程,并快速中止后续线程。但由于使用“const”并在低级别手动处理锁定标志,它似乎不是很 C#-ish。有没有更好的办法?
这基本上是 lock() 功能的直接复制,但使用非阻塞 Interlocked.Exchange,而不是使用阻塞 Monitor.Enter()
public class FooGoo
{
private const int LOCKED = 0; // could use any arbitrary value; I choose 0
private const int UNLOCKED = LOCKED + 1; // any arbitrary value, != LOCKED
private static int _myLock = UNLOCKED;
void myEventHandler()
{
int previousValue = Interlocked.Exchange(ref _myLock, LOCKED);
if ( previousValue == UNLOCKED )
{
try
{
// some handling code, which may or may not return quickly
// maybe not threadsafe
}
finally
{
_myLock = UNLOCKED;
}
}
else
{
// another thread is executing right now. So I will abort.
//
// optional and environment-specific, maybe you want to
// queue some event information or set a flag or something,
// so you remember later that this thread aborted
}
}
}
【问题讨论】:
-
我刚刚发现:lock() 是 System.Threading.Monitor.Enter(x) 的快捷方式;尝试 { ... } 最后 { System.Threading.Monitor.Exit(x);所以这已经是一个改进,消除了 const。我想剩下的唯一一件事就是问,是否存在任何类型的非阻塞快捷方式,例如 lock() 来缩短上述所有内容?
-
事件触发不使用线程池。
-
@JohnSaunders 至少,由 system.timers.timer 产生的事件在线程池线程上执行,正如查看 Thread.CurrentThread.IsThreadPoolThread 所证实的那样。但无论如何,这个细节并不是问题的核心。
-
我敢打赌,定时器事件不是在线程池线程上执行的,而是了解定时器到期的 .NET 代码已经在线程池线程上运行。我相信您会发现,通常,事件是在检测到事件的同一线程上引发的。
-
@JohnSaunders 再次,这并不重要,这只是一个切线,但为了测试这一点,我创建了一个新的控制台应用程序,并在 Main() 内部创建了一堆计时器,并且在事件处理方法中,显示有关当前线程的信息。为了防止应用程序死机,我将原始线程置于无限睡眠状态。
标签: c# multithreading events thread-safety threadpool