使用委托异步执行遭遇多个请求时抛异常

1.最近做的一个小功能是将请求拦截并记录日志,因为要尽可能减少对请求的响应时间,所以自然选择异步执行,我使用的是IAsyncResult模式。到了prd产品测试环境,因为同时有多个请求,所以暴露了一个问题。

抛出了如下异象:The IAsyncResult object provided does not match this delegate

最后找到了解决方案http://zen-and-art-of-programming.blogspot.tw/2012/04/async-callback-trap.html#!/2012/04/async-callback-trap.html

The code present in the class below shows use of AsyncCallback in .NET to load forms (say fixed document in WPF).

public class FormLoader : IFormLoader

{

…//Other code here

private Action _InvokeFormLoad;

…//Other code here

private void OnPreFormLoaded()

{

_InvokeFormLoad = InvokeFormLoad;

AsyncCallback callBack = new AsyncCallback(InvokeFormLoadCallBack);

_InvokeFormLoad.BeginInvoke(callBack, null);

}

private void InvokeFormLoadCallBack(IAsyncResult asyncResult)

{

_InvokeFormLoad.EndInvoke(asyncResult);

}

…//Other code here

}

When we look at this code, it seems to work as expected and load forms asynchronously. If we take a much closer look, there is a pitfall.

_InvokeFormLoad being a private member, is not thread safe. In this case threads are created by the framework and not the user.

This leads to System.InvalidOperationException:

  The IAsyncResult object provided does not match this delegate.

Suppose if thread T1 from the thread pool calls _InvokeFormLoad.BeginInvoke(). Assume that another thread T2 calls BeginInvoke() before T1 calls EndInvoke() on _InvokeFormLoad. This causes the above mentioned Invalid Operation Exception.

In order to avoid this we need to adopt the following pattern.

  1. Copy the reference of the delegate to another variable say invokeFormLoad2.
  2. Instead of registering a callback, define an anonymous method and call the EndInvoke() on the copied reference variable as shown below.

private void OnPreFormLoaded()

{

_InvokeFormLoad = InvokeFormLoad;

Action invokeFormLoad2 = _InvokeFormLoad;

_InvokeFormLoad.BeginInvoke(delegate(IAsyncResult result)

{

invokeFormLoad2.EndInvoke(result);

},

null);

}

Even when thread T2 changes the reference _InvokeFormLoad to point to a different object T1 calls EndInvoke() on the correct object.

2.今天还碰到一个问题XML序列化的时候,使用的StringBuilder对象导致了内存溢出。没找到比较好的解决办法,

因为只要对象足够大的时候,就会有内存溢出的异常。

作者:张雪飞
出处:https://zhangxuefei.site/p/66
版权说明:欢迎转载,但必须注明出处,并在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

发表评论

电子邮件地址不会被公开。 必填项已用*标注