取消对象上的锁定

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

这可能很简单,但目前还无法弄清楚。

简单来说:

我的存储库层中有一个长时间运行的操作(大约 8 分钟)。

public static ReleaseSelection LoadedReleaseSelection = new ReleaseSelection();
private static object s_cacheLock = new object();

public Long Load(ReleaseSelection releaseSelection)
{
    //check if the release passed in to load is different the one previously loaded
    if (releaseSelection != LoadedReleaseSelection)
    {
        //do something to break the lock(s_cacheLock)
    }

    lock (s_cacheLock)
    {
        //Reads from TAB files and put them into cache objects.. runs for about 8 mins

        LoadedReleaseSelection = releaseSelection;
    }
}

服务层异步调用Load

 public Task<long> LoadAsync()
{
    ReleaseSelection releaseSelection = //get value from db through another repo call

    if (releaseSelection == null)
    {
        return null;
    }

    return Task.Factory.StartNew(() => m_releaseRepository.Load(releaseSelection));
} 

最后,该服务由 API 端点调用

public async Task<IHttpActionResult> ReleaseLoadPost()
{
    await m_releaseService.LoadAsync();
    return Ok();
}

当以下条件成立时,我如何取消加载操作(第一个代码块)中的

lock(s_cacheLock)

//check if the release passed in to load is different the one previously loaded
if (releaseSelection != LoadedReleaseSelection)
{
    //do something to break the lock(s_cacheLock)
}

这样另一个线程就不必等待之前的加载完成?

注意:我需要

lock(m_cacheLock)
因为我还有其他从缓存中读取的方法,并且在加载所有缓存之前不应该这样做。

c# multithreading locking cancellation
3个回答
0
投票

不需要使用锁来保护8分钟的加载过程,只需在加载完成后锁定更新缓存集语句即可。您还应该使用

CancellationToken
取消加载过程,并在加载过程中定期检查令牌取消状态。


0
投票

另一种选择是进行一些重构并使用 SemaphoreSlim,它有一个 Wait(CancellationToken) 方法。

如果你看一下底层代码,它会做一堆尝试高效地完成任务(通过 SpinWait,然后使用 Monitor 和 WaitHandle),但如果所有其他方法都失败,它确实会启动自己的异步任务,该任务将在以下情况下被取消:您的取消令牌已被取消。这是一种您通常不希望自己实现和测试/调试的代码,并且在 .NET 版本上明显以各种方式演变。


-1
投票

使用Monitor.Enter & Monitor.Exit代替锁,确保捕获异常并释放锁。

示例:

Monitor.Enter(s_cacheLock)

// do work

Monitor.Exit(s_cacheLock)
© www.soinside.com 2019 - 2024. All rights reserved.