本文介绍了使用的await时Monitor.Exit SynchronizationLockException的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我创建了一块code的,从遗留系统,我们有得到一个网页。为了避免过多的查询,我缓存得到的URL。我使用 Monitor.Enter Monitor.Exit 和双重检查,以避免请求发出两次,但是当释放与 Monitor.Exit 锁,我得到这个异​​常:

I am creating a piece of code that gets a webpage from a legacy system we have. In order to avoid excessive querying, I am caching the obtained URL. I am using Monitor.Enter, Monitor.Exit and double checking to avoid that request is issued twice, but when releasing the lock with Monitor.Exit, I am getting this exception:

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 。这是code执行操作:

The line 56 is the Monitor.Exit. This is the code that performs the operation:

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);
        }
    }
}

那么,什么是问题伺机显示器?是不是因为它是不一样的线程时 Monitor.Enter 比当 Monitor.Exit

So what is the problem with await and Monitor? Is it because it is not the same thread when Monitor.Enter than when Monitor.Exit?

推荐答案

您不能等待 A 锁内的任务范围(这是 Monitor.Enter 和 Monitor.Exit )。使用显示器将直接骗过编译器而不是框架。

You can't await a task inside a lock scope (which is syntactic sugar for Monitor.Enter and Monitor.Exit). Using a Monitor directly will fool the compiler but not the framework.

异步等待有像显示器没有线程亲和力一样。在code中的后等待可能会在不同的线程比收到code运行。这意味着,释放显示器线程不一定是收购它的人。

async-await has no thread-affinity like a Monitor does. The code after the await will probably run in a different thread than the code before it. Which means that the thread that releases the Monitor isn't necessarily the one that acquired it.

要么不使用异步等待在这种情况下,或者使用不同的同步建设,比如 SemaphoreSlim 或一个 AsyncLock ,你可以建立你自己。这里是我的:

Either don't use async-await in this case, or use a different synchronization construct like SemaphoreSlim or an AsyncLock you can build yourself. Here's mine: http://stackoverflow.com/a/21011273/885318

这篇关于使用的await时Monitor.Exit SynchronizationLockException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

09-24 16:29