【发布时间】:2012-06-06 12:04:57
【问题描述】:
在我正在调用的 Parallel.Foreach 循环中
_helper.subscribeUserEndPoint(loop._contactGrpSvcs);
_helper 是 UserEndPoint 和所有其他操作(如订阅)的封装类
订阅方法是:
public void subscribeUserEndPoint(ContactGroupServices cntGrpSvcs)
{
cntGrpSvcs.BeginSubscribe(TerminateSubscribe, cntGrpSvcs);
_contactSubscribeCompleted.WaitOne();
LOG.Info("Returning from Successful Subscribe Endpoint");
}
private void TerminateSubscribe(IAsyncResult result)
{
ContactGroupServices cntGrpSvcs = result.AsyncState as ContactGroupServices;
try
{
cntGrpSvcs.EndSubscribe(result);
}
catch (Exception ex)
{
LOG.Error("Failed to Complete Subscribe. " + ex.StackTrace);
}
CollaborationSubscriptionState state = cntGrpSvcs.CurrentState;
LOG.Info("Subscribed State = " + state.ToString());
_contactSubscribeCompleted.Set();
}
等待_contactSubscribeCompleted.WaitOne()时的线程死锁;有什么方法可以避免这种死锁争用?
干杯,
-- Brian
PS:可能发生死锁的一个原因是 AutoResetEvent 的固有问题——从文档中——“不能保证每次调用 Set 方法都会释放一个线程。如果两个调用太紧靠在一起,这样第二次调用发生在一个线程被释放之前,只有一个线程被释放。就好像第二次调用没有发生一样。另外,如果在没有线程等待并且AutoResetEvent已经发生的情况下调用Set发出信号,呼叫无效。“有解决方法吗??
【问题讨论】:
-
这不是死锁。当两个线程需要访问被另一个线程锁定的资源时,就会发生死锁。这不是这里的情况
-
是什么让你认为这是一个死锁而不仅仅是一个块?要了解死锁,我们需要了解两个线程之间的交互。我认为这不会导致死锁,因为
TerminateSubscribe从不尝试获取竞争锁。 -
对 TerminateSubscribe 的调用在哪里? BeginSubscribe 是否曾调用 TerminateSubscribe?
-
正如 Marc 指出的那样,这很可能只是一个块,因为两个 AutoResetEvent 集从彼此靠近的两个线程转到一个线程的 WaitOne,而第二个线程仍在等待。
-
为什么还要在这里使用等待句柄,你不能只做
cntGrpSvcs.EndSubscribe(cntGrpSvcs.BeginSubscribe(null, null))吗? (加上一些异常处理/记录)
标签: c# multithreading autoresetevent ucma