我正在创建一段代码,从我们拥有的遗留系统中获取网页。为了避免过多的查询,我对获取到的URL进行了缓存。我在用Monitor.Enter
, Monitor.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);
}
}
}
那么问题出在哪里await
and Monitor
?是不是因为不是同一个线程的时候Monitor.Enter
比当Monitor.Exit
?
你不能await
a 内的任务lock
范围(这是语法糖Monitor.Enter
and Monitor.Exit
)。用一个Monitor
直接会欺骗编译器,但不会欺骗框架。
async-await
没有像 a 这样的线程亲和力Monitor
做。后面的代码是await
可能会在与之前的代码不同的线程中运行。这意味着释放该线程Monitor
不一定是获得它的人。
要么不使用async-await
在这种情况下,或者使用不同的同步结构,例如SemaphoreSlim
or an AsyncLock
你可以自己建造。这是我的:https://stackoverflow.com/a/21011273/885318 https://stackoverflow.com/a/21011273/885318
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)