我正在創建一段從舊版系統獲取網頁的代碼。爲了避免過多的查詢,我緩存了獲取的URL。我使用Monitor.Enter
,Monitor.Exit
和雙重檢查,以避免請求發出了兩次,但Monitor.Exit
解除鎖定的時候,我得到這個異常:使用await時Monitor.Exit上的SynchronizationLockException
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
和Monitor
問題?是因爲Monitor.Enter
比Monitor.Exit
的線程不一樣嗎?
它應該與一個ManualResetEventSlim? – vtortola
它可以,但是將SemaphoreSlim設置爲1會容易得多,因爲您可以等待它,並且它不是線程仿製的 – i3arnon
感謝您的解釋。這很有道理。 – vtortola