我在.Net 4.0 C#应用程序中对一个Web服务进行了两次异步调用。这些是使用AutoResetEvent WaitOne()
控制的。
在我的本地机器上,这是按预期工作的。但是当我在服务器中部署它时,第一步调用第二步的成功处理程序。
要让线程正常运行需要做哪些更改?
if (userID != null)
{
AddressBookRequest req = new AddressBookRequest
{
contactsSearchCriteria = new ContactsSearchCriteria
{
searchUserID = userID.Trim()
},
HeaderParams = new HttpHeaderParms
{
UserId = userID.Trim(),
UserPrincipalName = userID.Trim() ,
ContentType = "application/xml"
}
};
lookupServicesAssociate.SearchContactDetailsAsync(req);
autoRestEvent = new AutoResetEvent(false);
lookupServicesAssociate.SearchContactDetailsCompleted +=
new EventHandler<ServiceResponseEventArgs<ContactDetailsPreview[]>>(AssociateSearchContactDetailsCompleted);
autoRestEvent.WaitOne();
}
if (reportsToUserID != null)
{
AddressBookRequest req1 = new AddressBookRequest
{
contactsSearchCriteria = new ContactsSearchCriteria
{
searchUserID = reportsToUserID.Trim()
},
HeaderParams = new HttpHeaderParms
{
UserId = reportsToUserID.Trim(),
UserPrincipalName = reportsToUserID.Trim(),
ContentType = "application/xml"
}
};
lookupServiceReports.SearchContactDetailsAsync(req1);
lookupServiceReports.SearchContactDetailsCompleted +=
new EventHandler<ServiceResponseEventArgs<ContactDetailsPreview[]>>(ReportsToAssociateSearchContactDetailsCompleted);
autoRestEvent.WaitOne();
}
答案 0 :(得分:2)
如果我正确阅读您的代码,您就会遇到危险的竞争条件。你有:
lookupServicesAssociate.SearchContactDetailsAsync(req);
autoRestEvent = new AutoResetEvent(false);
lookupServicesAssociate.SearchContactDetailsCompleted +=
new EventHandler<ServiceResponseEventArgs<ContactDetailsPreview[]>>(AssociateSearchContactDetailsCompleted);
autoRestEvent.WaitOne();
在第一行中,您调用异步方法。然后,创建AutoResetEvent
并分配事件处理程序。
如果在分配回调之前完成SearchContactDetailsAsync
,则WaitOne
将永远不会完成,因为回调将不会被执行且事件永远不会发出信号。
你真的应该写:
autoRestEvent = new AutoResetEvent(false);
lookupServicesAssociate.SearchContactDetailsCompleted +=
new EventHandler<ServiceResponseEventArgs<ContactDetailsPreview[]>>(AssociateSearchContactDetailsCompleted);
lookupServicesAssociate.SearchContactDetailsAsync(req);
autoRestEvent.WaitOne();
虽然说实话,但我想知道你为什么要开始异步任务然后等待它完成。你有效地同步了。
所有这一切,我必须同意Pako的评论:除非UserID == null
,否则不会发生这种情况。这引发了另一个潜在的问题:如果autoResetEvent
是null
和UserID == null
,则第二个WaitOne
会抛出NullReferenceException
。如果多个线程正在执行此代码,则每个线程将创建一个不同的AutoResetEvent
,这肯定会导致问题,因为您可能最终等待一个永远不会发出信号的事件,或者等待错误的事件并捕获别人的信号。