簡體   English   中英

跨異步塊代碼使用 AutoResetEvent 安全嗎?

[英]Is using AutoResetEvent across async block code safe?

我試圖鎖定我的同步代碼部分並釋放異步代碼塊中的鎖(在執行任務后)。 我已經閱讀了“AutoResetEvent”,並希望在代碼實現的調用者和被調用者之間實現其信號功能。

目的是鎖定負責驗證之前是否管理過事務的代碼。 檢查完成並保存交易后,我發布代碼。 檢查和保存操作是異步的,鎖釋放發生在'continueWith'委托function。

我有以下 AutoResetEvent 的抽象和實現:

public interface IThreadLockKeyProvider { public AutoResetEvent PayLock { get; } }

public class ThreadLockKeyProvider : IThreadLockKeyProvider
{
    public static readonly AutoResetEvent _payLock;

    static ThreadLockKeyProvider()
    {
        _payLock = new AutoResetEvent(true);
    }

    public AutoResetEvent PayLock { get { return _payLock; } }
}

該實例作為 singleton 注入到 .net 核心依賴注入容器中。

事件處理方法的代碼如下:

    public Task<Unit> Handle(ProcessPaymentCommand command, CancellationToken cancellationToken)
    { 

        _threadLockKeyProvider.PayLock.WaitOne();

        var res = _brandDepositStrategy.AdministerDeposit().Result; 

        return Task.FromResult(Unit.Value);
    }

釋放鎖的 AdministerDeposit 方法。

   public override async Task<Task> AdministerDeposit()
    {
        Task<PaymentTransactions> dbOperation = _transactionAdministrationFacade.UpdateDbTransactionAsync(_IPNRequestDto);

        return await dbOperation.ContinueWith(async x =>
        {

            _threadLockKeyProvider.PayLock.Set();

            if (x.IsFaulted)
                throw x.Exception;

            _transactionAdministrationFacade.CallBackDto = await _responseComposer.GetPaymentResponseDto(x.Result, _IPNRequestDto);

            await CreateDepositSF();
        });
    }

問題是執行會不會有什么問題?

注意:代碼確實有效。 它不會崩潰並通過我構建的單元測試。

理論上,在這種情況下AutoResetEvent沒有任何問題,但是:它並不是完全為異步構建的,這意味着您的WaitOne()阻塞了一個線程——這正是您要避免的。 同樣,您正在使用異步同步。 因為這基本上是一個異步鎖,所以看到入口/出口相距如此之遠讓我很擔心——這很容易引入錯誤。

讓我們嘗試解決這些問題:

  1. 使用SemaphoreSlim作為異步友好鎖
  2. await我們的結果
  3. 將鎖的入口/出口移動到同一個地方

例子:

private readonly SemaphoreSlim _lock = new(1, 1);

public async Task<int> SomeOuterMethodAsync(CancellationToken cancellationToken)
{
    await _lock.WaitAsync(cancellationToken);
    try
    {
        var s = await SomeInnerMethodAsync(cancellationToken);
        return s.Length; // just some projection
    }
    finally
    {
        _lock.Release();
    }
}

// note: this could be in unrelated types/instances/etc
private Task<string> SomeInnerMethodAsync(CancellationToken cancellationToken)
    => throw new InvalidOperationException("not shown");

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM