开发者

accessing disposed object

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:

  1. Another SO Question
  2. Wikipedia article
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜