我有多个代码块,类似于以下内容:
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布尔值。但是,我想谈一些更通用的东西,但有点不确定如何继续。
我最初的想法是设置一个函数,将上面的代码作为委托,但我总是被奇怪的语法陷入困境。我喜欢这样的功能,我只需将整个事物包装起来并将其作为匿名方法传递给我的函数,然后在该函数和回调中处理我的类的繁忙状态。
感谢任何帮助,谢谢。
答案 0 :(得分:3)
如果您正在寻找的是指示某些内容正在使用中,那么您最好使用计数器而不是简单的布尔标志。然后,您可以使用Interlocked.Increment
和Interlocked.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)
使用计数器并在每次开始和减少时递增,确保你使比赛安全