我遇到一种情况,我需要在 2 个方法中的 1 个方法结束时执行一些代码 - 以第二个完成者为准。我的特殊情况是 Blazor 服务器,我需要在 OnInitializedAsync()/ OnAfterRenderAsync() 末尾执行此代码。在这种情况下,代码取决于可调用的 JavaScript 以及完全从数据库填充的页面模型。
我想出了以下课程来完成此任务:
public class DoubleFinish
{
private volatile bool _firstFinished = false;
private volatile bool _secondFinished = false;
private volatile bool _alreadyReturnedTrue = false;
/// <summary>
/// Call when the first method completes. Returns true if the 2nd method is also
/// complete and so this method can now run the code that requires both methods.
/// </summary>
public bool TryFirstFinished
{
get
{
lock (this)
{
_firstFinished = true;
if (_alreadyReturnedTrue || ! _secondFinished)
return false;
_alreadyReturnedTrue = true;
return true;
}
}
}
/// <summary>
/// Call when the second method completes. Returns true if the 1st method is also
/// complete and so this method can now run the code that requires both methods.
/// </summary>
public bool TrySecondFinished
{
get
{
lock (this)
{
_secondFinished = true;
if (_alreadyReturnedTrue || ! _firstFinished)
return false;
_alreadyReturnedTrue = true;
return true;
}
}
}
}
然后,我在 razor.cs 文件中包含以下内容(这两个方法可以位于不同的任务中,因此可以同时执行):
OnInitializedAsync() {
// ... lots of DB access
if (DoubleFinish.TryFirstFinished)
await OnAfterInitializeAndRenderAsync();
}
OnAfterRenderAsync(bool firstRender) {
if (!firstRender)
return;
if (DoubleFinish.TrySecondFinished)
await OnAfterInitializeAndRenderAsync();
}
我有两个问题:
- 我需要在 中声明布尔值吗
DoubleFinish
volatile
? - 是否有某种原子调用来检查/设置避免使用的 bool 值
lock
?
更新:一个主要限制。OnInitializedAsync()
在某些配置中可以被调用两次。所以我不能使用计数器。我必须具体跟踪每个方法是否已完成。
我认为使用该
Interlocked.Decrement
方法会更简单,并自动减少整数计数器。当计数器减至零时,您可以确定最后一个挂起的操作已完成:更新:如果这两个方法中的每一个都可以被调用多次,它会变得更加复杂,但您仍然可以使用该类
Interlocked
。以下是该类型的原子按位 OR运算的实现uint
:它可以这样使用:
你可以做的一件事是使用
Interlocked.Increment
:或
SemaphoreSlim
或AsyncCountdownEvent
从Nito.AsyncEx.Coordination
. 类似于以下内容(如果在 Blazor 上下文中可行):UPD
如果
OnInitializedAsync
可以运行多次,那么您的解决方案应该没问题。请注意,您应该避免使用lock(this)
,只需创建一个private object _locker = new object();
用于锁定的字段,并且不需要 volatile ,因为您仅在锁内部使用布尔值。或者你可以玩这样的怪物(尽管我会坚持使用锁定):