i am using following cla开发者_开发技巧ss to provide access to language resources in an asp.net application. i render the page for selected language by getting the text values from database. so i try to optimize fetching texts by caching them in a static datatable. However, i am not sure whether its always safe to read from tableResources that it may be re-created by UpdateResources function. I know GC will not release the object when its read by Rows.Find but i don't know much about GC. It may cause a deadlock or stuck GC, whatever else. (I think IL instructions are not atomic, unless the ones that compiled to a single CPU instruction). Please, help me to comprehend this.
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;
}
}
}
}
I have used the following class instead of DataTable. After setting new instance of object, i have forced garbage collection by
GC.Collect();
GC.WaitForPendingFinalizers();
If AMethod() is called then destructor of DataTableX is not called but if its not then destructor is called.
I have tested even while objDataTableX.AMethod() is about to be called. I have stepped into the disassembly code and freeze debugger when objDataTableX reference is fetched by a single instruction and then continue debugging with another thread that changes the reference. Reference is changed but previous DataTableX reference is not disposed so i thaw the other thread and it executes well with the previous reference.
public class DataTableX
{
public void AMethod()
{
}
~DataTableX()
{
}
}
I think you want to achieve that the callers of the index property aren't disturbed by a parallel call to the UpdateResources-function from another thread.
Your single lock-statement has no effect at all. When you want to synchronize the access of the tableResources member - you have to do synchronize all places where its being accessed (UpdateResources and index property).
When you don't synchronize there might be a raise condition, because when you call UpdateResources, there is no reference to the old DataSet - even when tableResources.Rows.Find(resourceCode) is executing at that time.
In addition you should modify the access modifier of tableResources to private or protected.
Concerning performance, you might want to implement a more complex synchronization mechanism which fits better to the multiple-readers-single-writer pattern. See these links:
- Another SO Question
- Wikipedia article
精彩评论