SynchronizationLockException on Monitor.Exit when using await(使用等待时 Monitor.Exit 上的 SynchronizationLockException)
问题描述
我正在创建一段代码,用于从我们拥有的旧系统中获取网页.为了避免过度查询,我将获取到的 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:UsersmeDocumentsVisual Studio 2013ProjectsMyAppMyAppDataExProvider.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:UsersmeDocumentsVisual Studio 2013ProjectsMyAppMyAppDataExProvider.cs:line 71
InnerException:
第 56 行是 Monitor.Exit.这是执行操作的代码:
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);
}
}
}
那么 await 和 Monitor 有什么问题呢?是不是因为 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?
推荐答案
你不能在 lock 范围内 await 任务(这是 的语法糖>Monitor.Enter 和 Monitor.Exit).直接使用 Monitor 会欺骗编译器,但不会欺骗框架.
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.
async-await 没有像 Monitor 那样的线程亲和性.await 之后的代码可能会在与之前的代码不同的线程中运行.这意味着释放 Monitor 的线程不一定是获取它的线程.
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.
在这种情况下不要使用 async-await,或者使用不同的同步结构,如 SemaphoreSlim 或您可以构建的 AsyncLock你自己.这是我的:https://stackoverflow.com/a/21011273/885318
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: https://stackoverflow.com/a/21011273/885318
这篇关于使用等待时 Monitor.Exit 上的 SynchronizationLockException的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:使用等待时 Monitor.Exit 上的 SynchronizationLockException
基础教程推荐
- SSE 浮点算术是否可重现? 2022-01-01
- 将 XML 转换为通用列表 2022-01-01
- rabbitmq 的 REST API 2022-01-01
- 如何激活MC67中的红灯 2022-01-01
- MS Visual Studio .NET 的替代品 2022-01-01
- c# Math.Sqrt 实现 2022-01-01
- 有没有办法忽略 2GB 文件上传的 maxRequestLength 限制? 2022-01-01
- 为什么Flurl.Http DownloadFileAsync/Http客户端GetAsync需要 2022-09-30
- 将 Office 安装到 Windows 容器 (servercore:ltsc2019) 失败,错误代码为 17002 2022-01-01
- 如何在 IDE 中获取 Xamarin Studio C# 输出? 2022-01-01
