2014-02-13 5 views
1

Я пытаюсь синхронизировать webapi, который будет служить изображениям. Когда я запрашиваю конкретное изображение, он проверяет, существует ли изображение уже и возвращает ли оно его, или если оно не существует, оно создаст его, а затем вернет его..net. Синхронизация доступа к файлам

Моя проблема в том, что это явно не потокобезопасно; У меня есть один поток, и определение образа не существует и начинает его создавать, в то время как другой запрос приходит, а также определяет, что изображение не существует (пока) и пытается его создать. Я знаю, что я мог бы заблокировать все это, чтобы избежать проблемы, но я стараюсь избегать этого. Будет 100 000 изображений, и я не понимаю, почему мне нужно остановить все потоки от чтения других изображений только потому, что одно изображение еще не существует. Есть ли «обычный» способ сделать это? Изображения запрашиваются идентификаторами, можно ли заблокировать идентификатор определенного изображения? Например,

List<long> _locks = new List<long>(); 
_locks.Add(17); 
lock(_locks[0]){...} 

Это просто не выглядит правильным ... конечно, есть лучшее решение?

+0

Что вы можете сделать, на вашем 'Read' добавьте 3 повторных цикла, за 2 секунды. Итак, если вы получаете «Исключение доступа к файлу», предположительно, когда файл написан, просто подождите и попробуйте снова прочитать. –

+0

@ T.S. спасибо, я подумал об этом, и это «резервное» решение, я думаю, но я хотел бы попытаться избежать исключения в первую очередь, если смогу. Я не много сделал с точки зрения многопоточности, поэтому просто пытаюсь выяснить, как это сделать правильно, я думаю. Пробовал блокировать всю секцию на одном (статическом) объекте, а среднее время отклика от 20 мс до 200 мс ... !! – Andy

ответ

2

Это зависит от настроек вашего сервера (одного или фермы). На одном сервере вы можете использовать общий HashSet. Имя файла - отличный ключ. Вам нужно всего лишь короткую блокировку вокруг набора, что не повредит работе.

Вот вопрос о concurrent HashSet

+0

Это хорошо сработало в конце. Это привело к тому, что avg-ответ снизился до 12 мс - конечно, лучше, чем 200 мс с блокировкой() и лучше, чем без управления (и, следовательно, с большим количеством ошибок) и 20 мс. Спасибо за вашу помощь. – Andy

0

Мой друг, вы хотите, чтобы избежать «попробовать на основе» подход, вы хотите, чтобы избежать «блокировки» подход и тем не менее, вы доступ к общему ресурсу. Попробуйте вызвать corflags на любой управляемой dll и оставьте окно командной строки вверх. Затем перейдите в Windows Explorer и попытайтесь удалить этот файл. Вы получите «файл в использовании». Даже Windows не полностью вышла из леса с файлами со всеми механизмами кэширования. Конечно, проблема в том, что все файлы проходят через один и тот же замок. Может быть, вы можете что-то сделать, чтобы свести к минимуму это условие. Посмотрим. Это совершенно непроверенная идея:

Создание пользовательских блокировки объект

public class CustomLock 
{ 
    private object _lock = new object(); 
    private string _file; 

    public CustomLock(string file) 
    {_file = file;} 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public object Read() 
    { 
     lock(_lock) 
     { 
      // read your file 
     } 
    } 

    public override int GetHashCode() 
    { 
     // here your hash algorithm 
    } 

} 

Теперь используйте HashTable с HashTable.Synchronized, как описано здесь http://msdn.microsoft.com/en-us/library/system.collections.hashtable.synchronized%28v=vs.110%29.aspx, иметь кэш ваших замков

Или вы можете синхронизировать Словарь What's the best way of implementing a thread-safe Dictionary? , Итак, теперь это будет что-то вроде этого:

var custLock = GetCustLock(file); // This should always return CustomLock object, new or existing 
object file = custLock.Read(); 

Предположительно, используя этот проект, вы будете удалить узкое место блокировки всех файлов в одном месте. Пожалуйста, проверьте его.

Смежные вопросы