第二个方法完成后如何执行代码

问题描述 投票:0回答:2

我遇到一种情况,我需要在 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();
}

我有两个问题:

  1. 我需要在
    DoubleFinish
    volatile
    中声明布尔值吗?
  2. 是否有某种原子调用来检查/设置 bool 值以避免使用
    lock

更新: 一个主要限制。在某些配置中,

OnInitializedAsync()
可以被调用两次。所以我不能使用计数器。我必须具体跟踪每个方法是否已完成。

c# multithreading thread-safety
2个回答
0
投票

我认为使用

Interlocked.Decrement
方法会更简单,并原子地减少整数计数器。当计数器减至零时,您可以确定最后一个挂起的操作已完成:

private int _pendingCount = 2;

OnInitializedAsync()
{
    // ...
    if (Interlocked.Decrement(ref _pendingCount) == 0)
        await OnAfterInitializeAndRenderAsync();
}

OnAfterRenderAsync(bool firstRender)
{
    // ...
    if (Interlocked.Decrement(ref _pendingCount) == 0)
        await OnAfterInitializeAndRenderAsync();
}

0
投票

您可以做的一件事就是使用

Interlocked.Increment
:

private int counter = 2;

OnInitializedAsync()
{
    // ...
    if (Interlocked.Increment(ref counter) == 2)
        YourCodeToRun();
}

OnAfterRenderAsync(bool firstRender)
{
    // ...
    if (Interlocked.Increment(ref counter) == 2)
        YourCodeToRun();
}

SemaphoreSlim
AsyncCountdownEvent
来自
Nito.AsyncEx.Coordination
。类似以下内容(如果在 Blazor 上下文中可行):

private AsyncCountdownEvent signal = new AsyncCountdownEvent(2);

Task.Run(async () =>
{
    await signal.WaitAsync();
    YourCodeToRun();
})

OnInitializedAsync()
{
    // ...
    signal.Signal();
}

OnAfterRenderAsync(bool firstRender)
{
    // ...
    signal.Signal();
}
© www.soinside.com 2019 - 2024. All rights reserved.