Самое простое объяснение, которое я могу дать:
В моем веб-приложении .NET1.1 я создаю файл на диске в методе Render и добавляю элемент в Cache, срок действия которого истекает, скажем, через минуту. У меня также есть метод обратного вызова, который вызывается по истечении срока действия элемента кэша, который удаляет файл, созданный с помощью Render. В методе Page_Init я пытаюсь получить доступ к файлу, который метод Render записал на диск. Оба эти метода имеют оператор блокировки, блокирующий закрытый статический объект.
Намерение:
Создать страницу, которая, по сути, записывает свою копию на диск, которая удаляется до того, как станет слишком старой (или устаревшей по содержанию), при обслуживании файла, если он существует на диске.
Наблюдаемая проблема:
Это действительно две проблемы, я думаю. Запрос страницы делает то, что я ожидаю, она рендерит страницу на диск и обслуживает ее немедленно, добавляя элемент срока действия в кеш. Для тестирования время истечения составляет 1 минуту.
Затем я ожидаю, что метод обратного вызова будет вызван через 60 секунд и удалит файл. Это не так.
Еще через минуту (ради аргумента) я обновляю страницу в браузере. Затем я могу увидеть, как вызывается метод обратного вызова, и установить блокировку на объект блокировки. Page_Init также вызывается и устанавливает блокировку на тот же объект. Однако оба метода, по-видимому, вводят свой блок кода блокировки и продолжают выполнение.
Это приводит к тому, что: рендер проверяет наличие файла, метод обратного вызова удаляет файл, метод рендеринга пытается обработать удаленный файл.
Ужасно упрощенный фрагмент кода:
public class MyPage : Page
{
private static Object lockObject = new Obect();
protected void Page_Init(...)
{
if (File.Exists(...))
{
lock (lockObject)
{
if (File.Exists(...))
{
Server.Transfer(...);
}
}
}
}
protected override void Render(...)
{
If (!File.Exists(...))
{
// write file out and serve initial copy from memory
Cache.Add(..., new CacheItemRemovedCallback(DoCacheItemRemovedCallback));
}
}
private static void DoCacheItemRemovedCallback(...)
{
lock (lockObject)
{
If (File.Exists(...))
File.Delete(...);
}
}
}
Может кто-нибудь объяснить это, пожалуйста? Я понимаю, что метод обратного вызова, по сути, является ленивым и, следовательно, вызывает только один раз, когда я делаю запрос, но, конечно, многопоточность в .NET1.1 достаточно хороша, чтобы не допустить одновременного входа двух блоков lock ()?
Спасибо
Мт.