我正在使用以下类来提供对asp.net应用程序中语言资源的访问。我通过从数据库中获取文本值来呈现所选语言的页面。所以我尝试通过在静态数据表中缓存来优化获取文本。但是,我不确定从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 :(得分:1)
我使用了以下类而不是DataTable。在设置了对象的新实例后,我通过
强制进行垃圾回收GC.Collect();
GC.WaitForPendingFinalizers();
如果调用AMethod(),则不会调用DataTableX的析构函数,但如果不调用它,则调用析构函数。
我即使在即将调用objDataTableX.AMethod()时也进行了测试。当单个指令获取objDataTableX引用时,我已进入反汇编代码并冻结调试器,然后继续使用另一个更改引用的线程进行调试。引用已更改,但之前的DataTableX引用未被处理,因此我解冻了另一个线程,并且它与之前的引用一起执行良好。
public class DataTableX
{
public void AMethod()
{
}
~DataTableX()
{
}
}
答案 1 :(得分:0)
我认为您希望实现index属性的调用者不会受到来自另一个线程的UpdateResources函数的并行调用的干扰。
您的单一锁定声明完全没有效果。 当您想要同步tableResources成员的访问权限时 - 您必须同步所有访问它的地方(UpdateResources和index属性)。
当你不同步时,可能会有一个提升条件,因为当你调用UpdateResources时,没有对旧DataSet的引用 - 即使当时正在执行tableResources.Rows.Find(resourceCode)。
此外,您应该将tableResources的访问修饰符修改为private或protected。
关于性能,您可能希望实现更复杂的同步机制,该机制更适合多读者单一作者模式。请参阅以下链接: