我正在创建一段代码,该代码可以从我们拥有的旧系统中获取网页。为了避免过多的查询,我正在缓存获取的URL。我正在使用Monitor.EnterMonitor.Exit和仔细检查以避免两次发出该请求,但是当使用Monitor.Exit释放锁时,出现此异常:

System.Threading.SynchronizationLockException was caught
  HResult=-2146233064
  Message=Object synchronization method was called from an unsynchronized block of code.
  Source=MyApp
  StackTrace:
       at MyApp.Data.ExProvider.<OpenFeature>d__0.MoveNext() in c:\Users\me\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Data\ExProvider.cs:line 56
    --- End of stack trace from previous location where exception was thrown ---
       at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
       at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
       at MyApp.Data.ExProvider.<GetSupportFor>d__15.MoveNext() in c:\Users\me\Documents\Visual Studio 2013\Projects\MyApp\MyApp\Data\ExProvider.cs:line 71
  InnerException:

第56行是Monitor.Exit。这是执行操作的代码:
private async Task<Stream> OpenReport(String report)
{
    var file = _directory.GetFiles(report+ ".html");
    if (file != null && file.Any())
        return file[0].OpenRead();
    else
    {
        try
        {
            Monitor.Enter(_locker);
            FileInfo newFile = new FileInfo(Path.Combine(_directory.FullName, report + ".html"));
            if (!newFile.Exists) // Double check
            {
                using (var target = newFile.OpenWrite())
                {
                    WebRequest request = WebRequest.Create(BuildUrl(report));
                    var response = await request.GetResponseAsync();
                    using (var source = response.GetResponseStream())
                        source.CopyTo(target);
                }
            }
            return newFile.OpenRead();
        }
        finally
        {
            Monitor.Exit(_locker);
        }
    }
}

那么awaitMonitor有什么问题呢?是因为Monitor.EnterMonitor.Exit时线程不同?

最佳答案

您不能在await范围(这是lockMonitor.Enter的语法糖)内对任务进行Monitor.Exit。直接使用Monitor将愚弄编译器,但不会愚弄框架。
async-await不像Monitor那样具有线程亲和性。 await之后的代码可能会在与其之前的代码不同的线程中运行。这意味着释放Monitor的线程不一定是获得它的线程。

在这种情况下,要么不使用async-await,要么使用其他可以自己构建的同步结构,例如SemaphoreSlimAsyncLock。这是我的:https://stackoverflow.com/a/21011273/885318

关于c# - 使用await时Monitor.Exit上的SynchronizationLockException,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/21404144/

10-12 14:47