使用通用委托挂钩异步调用

时间:2011-02-03 19:40:58

标签: c# delegates

我有多个代码块,类似于以下内容:

void GetPerson(Action<PersonView, Exception> callback);

...

IsBusy = true;
_personRequested = true;
_service.GetPerson((person, error) => 
{
 if (error != null)
  {
    return;
  }
  _person = person;
  _personLoaded = true;
  IsBusy = false;
});

我遇到的问题是,某个给定的类可能会触发多个不同的异步调用,并且IsBusy属性必须“智能”才能切换为仅因为调用'A'已完成,而是'B'并且'C'仍在等待中。因此_personRequested和_personLoaded布尔值。但是,我想谈一些更通用的东西,但有点不确定如何继续。

我最初的想法是设置一个函数,将上面的代码作为委托,但我总是被奇怪的语法陷入困境。我喜欢这样的功能,我只需将整个事物包装起来并将其作为匿名方法传递给我的函数,然后在该函数和回调中处理我的类的繁忙状态。

感谢任何帮助,谢谢。

3 个答案:

答案 0 :(得分:3)

如果您正在寻找的是指示某些内容正在使用中,那么您最好使用计数器而不是简单的布尔标志。然后,您可以使用Interlocked.IncrementInterlocked.Decrement以线程安全的方式修改值。

在班级宣布:

private volatile int isBusyCounter;

Interlocked.Increment(ref isBusyCounter);
_personRequested = true;
_service.GetPerson((person, error) => 
{
 if (error != null)
  {
    return;
  }
  _person = person;
  _personLoaded = true;
  Interlocked.Decrement(ref isBusyCounter);
});

(因为你要修改多个线程上的值,所以需要使用Interlocked,这可以确保更新不会相互冲突;我们不关心订单,因为你'无论是第一个还是另一个,都会以相同的值结束。

然后,检查IsBusy,而不仅仅是检查IsBusy > 0。变量需要为volatile,以便后续读取方法中的变量不会被优化掉(换句话说,如果您在循环中检查此条件或在给定函数内多次检查,那么我们将volatile放在那里以确保每次都检查该值而不是在本地缓存该值。

答案 1 :(得分:1)

我可能会考虑将布尔值和关于它们的逻辑包装成“状态机”或类似的东西: http://www.codeproject.com/KB/architecture/statepatterncsharp.aspx

答案 2 :(得分:0)

使用计数器并在每次开始和减少时递增,确保你使比赛安全