-1

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

我让自己像下面这样,但我想知道它是否正确构建

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];
    }
}

字典只会被初始化 1 次。以后不添加删除更新。

4

6 回答 6

3

快速浏览您的代码,在我看来,您的第一个问题将是公开可用的字典dicAuthorities。字典不是线程安全的。根据您要对该字典执行的操作,您需要实现一些东西来规范对它的访问。请参阅此相关问题:

使字典访问线程安全?

于 2013-01-10T22:22:39.713 回答
3

字典支持线程安全阅读。这是来自MSDN的证明:

只要不修改集合,字典就可以同时支持多个阅读器。即便如此,通过集合枚举本质上不是线程安全的过程。在枚举与写访问竞争的极少数情况下,必须在整个枚举期间锁定集合。要允许集合被多个线程访问以进行读写,您必须实现自己的同步。

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

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

于 2013-01-10T22:32:03.527 回答
3

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

  1. 启动时填写字典
  2. 在应用程序运行时使用该字典作为查找
  3. 启动后切勿添加或删除值

比你应该没问题。

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

因此,您的实现可能看起来像这样(将编码风格更改为对 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为声明本身添加了一个修饰符,因为这样可以确保它不会在运行时被另一个字典替换。

于 2013-01-10T22:33:21.623 回答
2

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

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

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

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

于 2013-01-10T22:37:00.833 回答
0

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

除此之外,很难说你是否csPublicFunctions是线程安全的,因为它取决于你如何处理调用中的数据库连接DbConnection.db_Select_DataTable

于 2013-01-10T22:25:16.433 回答
0

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

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

于 2013-01-10T22:36:36.607 回答