2009-11-09 7 views
1

Я использую следующий класс для обеспечения доступа к языковым ресурсам в приложении asp.net. Я выношу страницу для выбранного языка, получая текстовые значения из базы данных. поэтому я пытаюсь оптимизировать выборку текстов, кэшируя их в статическом datatable. Тем не менее, я не уверен, всегда ли он безопасен для чтения из tableResources, который может быть воссоздан функцией UpdateResources. Я знаю, что GC не выпустит объект, когда его прочитает Rows.Find, но я мало знаю о GC. Это может вызвать тупик или застревание GC, что бы то ни было. (Я думаю, что инструкции IL не являются атомарными, если только те, которые были скомпилированы для одной команды CPU). Пожалуйста, помогите мне понять это.доступ к удаленному объекту

public class Resources 
{ 
    public static DataTable tableResources; 
    public static object objSync = new object(); 
    private PageLangs PageLang; 

    static Resources() 
    { 
     UpdateResources(); 
    } 

    public Resources(PageLangs pageLang) 
    { 
     PageLang = pageLang; 
    } 

    public static void UpdateResources() 
    { 
     OleDbConnection con = ProjectLib.CreateDBConnection(); 
     try 
     { 
      con.Open(); 

      OleDbDataAdapter adap = new OleDbDataAdapter("SELECT Resource0,Resource1,Resource2,Resource3,Resource4,Resource5,Resource6,ResourceCode FROM Resources", con); 
      DataTable dt = new DataTable(); 
      adap.Fill(dt); 
      adap.Dispose(); 
      dt.PrimaryKey = new DataColumn[] { dt.Columns["ResourceCode"] }; 
      // DataTable is thread-safe for multiple reads but not for writes so sync. it. 
      lock (objSync) 
      { 
       tableResources = dt; 
      } 
     } 
     catch 
     { 
     } 
     finally 
     { 
      ProjectLib.CloseDBConnection(con); 
     } 
    } 

    public string this[string resourceCode] 
    { 
     get 
     { 
      try 
      { 
       DataRow row = tableResources.Rows.Find(resourceCode); 

       if (row != null) 
        return row[(int)PageLang] as string; 
       else 
        return resourceCode; 
      } 
      catch 
      { 
       return null; 
      } 
     } 
    } 
} 
+0

Начните с объяснения того, чего вы пытаетесь достичь. – RichardOD

+0

Извините, я забыл упомянуть, что я использую этот класс в приложении asp.net. Я выношу страницу для выбранного языка, получая текстовые значения из базы данных. поэтому я пытаюсь оптимизировать выборку текстов, кэшируя их в статическом datatable. – marksxer

+0

Я просто считаю, что было бы лучше выпустить адаптеры Fill() на таблицу без повторного создания, потому что Fill обновляет измененные строки из базы данных. Но я не уверен, что он просто обновляет существующие без повторного их создания. – marksxer

ответ

0

Я думаю, что вы хотите, чтобы добиться того, что абоненты из свойства индекса не нарушается параллельным вызовом к UpdateResources-функции из другого потока.

Ваш единственный фиксатор не имеет никакого эффекта. Если вы хотите синхронизировать доступ к элементу tableResources, вам необходимо выполнить синхронизацию всех мест, где к нему обращаются (UpdateResources и свойство индекса).

Если вы не синхронизируете, может возникнуть условие повышения, потому что при вызове UpdateResources ссылка на старый DataSet отсутствует, даже если в это время выполняется tableResources.Rows.Find (resourceCode).

Кроме того, вы должны изменить модификатор доступа tableResources к частному или защищенному.

Что касается производительности, возможно, вы захотите реализовать более сложный механизм синхронизации, который лучше подходит для шаблона с несколькими считывателями-одиночными писателями. Смотрите следующие ссылки:

  1. Другой SO Question
  2. Wikipedia article
+0

, но к нему уже обращается значение tableResources.Rows.Find, почему бы и нет ссылки на него. – marksxer

+0

Вам нужна ссылка снаружи объекта, чтобы предотвратить сбор мусора из объекта. В вашем опубликованном коде у вас есть только одна ссылка через переменную tableResources. Почему вы просто не синхронизируете чтения? Вы беспокоитесь о производительности? – Jan

+0

, но метод индексатора будет хранить ссылку tableResources до ее выхода. поэтому tableResources будет безопасным при запуске метода индексатора, и это не проблема, если его удалить и GCd после индексатора. Метод UpdateResources будет называться редко, поэтому его не беспокоит. Я не хочу синхронизировать чтение из-за производительности. он будет вызываться в asp.net-страницах несколько раз за запрос. – marksxer

1

Я использовал следующий класс вместо DataTable. После установки нового экземпляра объекта, я вынужден сбор мусора по

GC.Collect(); 
GC.WaitForPendingFinalizers(); 

Если AMethod() вызывается, то деструктор DataTableX не называется, но если его нет, то деструктор.

Я тестировал даже в то время, когда objDataTableX.AMethod() будет вызван. Я вступил в код разборки и заморозил отладчик, когда ссылка objDataTableX извлекается одной инструкцией, а затем продолжит отладку с другим потоком, который изменяет ссылку. Ссылка изменена, но предыдущая ссылка DataTableX не выбрана, поэтому я оттаиваю другой поток, и он отлично работает с предыдущей ссылкой.

public class DataTableX 
{ 
    public void AMethod() 
    { 
    } 

    ~DataTableX() 
    { 

    } 
}