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
- MoreLinq maxBy vs LINQ max + where 2022-01-01
- 良好实践:如何重用 .csproj 和 .sln 文件来为 CI 创建 2022-01-01
- 如何用自己压缩一个 IEnumerable 2022-01-01
- 带有服务/守护程序应用程序的 Microsoft Graph CSharp SDK 和 OneDrive for Business - 配额方面返回 null 2022-01-01
- Web Api 中的 Swagger .netcore 3.1,使用 swagger UI 设置日期时间格式 2022-01-01
- C#MongoDB使用Builders查找派生对象 2022-09-04
- 输入按键事件处理程序 2022-01-01
- WebMatrix WebSecurity PasswordSalt 2022-01-01
- 在哪里可以找到使用中的C#/XML文档注释的好例子? 2022-01-01
- C# 中多线程网络服务器的模式 2022-01-01
