适当的类定义和用法 - 线程安全 - ASP.net

时间:2013-01-10 22:18:49

标签: c# asp.net c#-4.0 thread-safety static-functions

我想知道如何正确定义一个类并安全地使用它。我的意思是当每个网站访问者进行数千个并发呼叫时安全线程。

我做了类似下面的事情,但我想知道它是否正确构建

public static class csPublicFunctions
{
    private static Dictionary<string, clsUserTitles> dicAuthorities;

    static csPublicFunctions()
    {
        dicAuthorities = new Dictionary<string, clsUserTitles>();
        using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
        {
            foreach (DataRow drw in dtTemp.Rows)
            {
                clsUserTitles tempCLS = new clsUserTitles();
                tempCLS.irAuthorityLevel = Int32.Parse(drw["Level"].ToString());
                tempCLS.srTitle_tr = drw["Title_tr"].ToString();
                tempCLS.srTitle_en = drw["Title_en"].ToString();
                dicAuthorities.Add(drw["authorityLevel"].ToString(), tempCLS);
            }
        }
    }

    public class clsUserTitles
    {
        private string Title_tr;
        public string srTitle_tr
        {
            get { return Title_tr; }
            set { Title_tr = value; }
        }

        private string Title_en;
        public string srTitle_en
        {
            get { return Title_en; }
            set { Title_en = value; }
        }

        private int AuthorityLevel;
        public int irAuthorityLevel
        {
            get { return AuthorityLevel; }
            set { AuthorityLevel = value; }
        }
    }

    public static clsUserTitles returnUserTitles(string srUserAuthority)
    {
        return dicAuthorities[srUserAuthority];
    }
}

字典只会被初始化一次。暂无添加删除更新。

6 个答案:

答案 0 :(得分:3)

快速查看代码,在我看来,您的第一个问题是公开的字典dicAuthorities。字典不是线程安全的。根据您对该词典的要求,您需要实现一些管理对它的访问。请参阅此相关问题:

Making dictionary access thread-safe?

答案 1 :(得分:3)

Dictionary支持线程安全读取。以下是MSDN的证明:

  

字典可以同时支持多个读者,   只要集合没有被修改。即便如此,列举   通过集合本质上不是一个线程安全的过程。在   枚举与写访问争用的罕见情况   必须在整个枚举期间锁定集合。允许的   多个线程可以访问的集合,用于读写   你必须实现自己的同步。

所以,如果你打算只从中读取数据,它应该可以工作。但是,我不相信您的词典只填充一次,并且在您的申请工作期间不会被修改。在这种情况下,此线程中的所有其他人都是正确的,有必要同步访问此字典,最好使用ConcurrentDictionary对象。

现在,我想谈谈设计本身。如果您想在用户之间存储共享数据,请使用专为此目的而设计的ASP.NET Cache

答案 2 :(得分:3)

正如其他人所说,Dictionary<TKey,TValue>本质上不是线程安全的。但是,如果您的使用方案是:

  1. 在启动时填写字典
  2. 在应用程序运行时将该字典用作查找
  3. 从不在启动后添加或删除值
  4. 比你应该没事。

    但是,如果您使用.net 4.5,我建议使用ReadOnlyDictionary

    来制作#3

    因此,您的实现可能看起来像这样(将编码风格更改为更友好的C#)

    private static readonly ReadOnlyDictionary<string, UserTitles> authorities;
    
    static PublicFunctions()
    {
        Dictionary<string, UserTitles> authoritiesFill = new Dictionary<string, clsUserTitles>();
        using (DataTable dtTemp = DbConnection.db_Select_DataTable("select * from myTable"))
        {
            foreach (DataRow drw in dtTemp.Rows)
            {
                UserTitles userTitle = new UserTitles
                {
                  AuthorityLevel = Int32.Parse(drw["Level"].ToString()),
                  TitleTurkish = drw["Title_tr"].ToString();
                  TitleEnglish = drw["Title_en"].ToString();
                }
                authoritiesFill.Add(drw["authorityLevel"].ToString(), userTitle);
            }
        }
        authorities = new ReadOnlyDictionary<string, UserTitles>(authoritiesFill);
    }
    

    我还在声明本身添加了一个readonly修饰符,因为这样你就可以确保它不会在运行时由另一个字典替换。

答案 3 :(得分:2)

不,您的代码不是线程安全的。

  • [ EDIT 不适用 - 在静态构造函数中设置/创建]字典(由System Down answer指示)在更新时不是线程安全的。字典不是只读的 - 因此无法保证它不会随着时间的推移而被修改。
  • [ EDIT 不适用 - 在静态构造函数中设置/创建]初始化不受任何锁保护,因此您最终会同时进行多次初始化
  • 您的参赛作品是可变的 - 因此,如果您获得每个参赛作品的一致价值,则很难理由
  • [ EDIT 不适用 - 仅在静态构造函数中修改]保存字典不是只读的字段 - 取决于代码,如果不缓存指向字典本身的指针,可能会导致数据不一致。

附注:尝试遵循C#的编码指南并调用以大写MySpecialClass开头的类,并且具有反映类的目的的名称(或明确的示例名称)。

编辑:我的大部分要点都不适用,因为字典的唯一初始化是静态构造函数。从线程安全的角度来看,这使得初始化安全。 请注意,静态构造函数内的初始化将在“首次使用前”的非确定性时刻发生。它可能导致意外行为 - 即,当访问DB时可能使用错误的“当前”用户帐户。

答案 4 :(得分:0)

你的问题的答案是否定的,它不是线程安全的。 Dictionary不是线程安全的集合。如果要使用线程安全字典,请使用ConcurrentDictionary

除此之外,很难说你的csPublicFunctions是否是线程安全的,因为它取决于你在DbConnection.db_Select_DataTable

的调用中处理数据库连接的方式

答案 5 :(得分:0)

仅公共Dictionary没有线程安全问题。 是的,字典填充是线程安全的。但是这个字典的另一个修改不是线程安全的。如上所述 - ConcurrentDictionary可以提供帮助。

您的类clsUserTitles的另一个问题也不是线程安全的。 如果clsUserTitles仅用于阅读,则可以将每个属性设置器clsUserTitles设为私有。并从clsUserTitles构造函数初始化这些属性。