Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/264.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 静态集合的线程安全加载_C#_Asp.net_Thread Safety - Fatal编程技术网

C# 静态集合的线程安全加载

C# 静态集合的线程安全加载,c#,asp.net,thread-safety,C#,Asp.net,Thread Safety,我有一些静态字典对象,它为我保存了一些常量列表,这样我就不必每次加载网站时都从数据库中加载它们(例如:国家列表、类别列表) 因此,我有一个静态函数,它检查实例是否为null,如果为null,则查询数据库,实例化静态变量,并用数据填充它 由于它是一个网站,因此可能会有一种情况,即当对象为空时,多人同时尝试访问该信息,所有这样做的人都会同时调用该进程(这实际上是不必要的,会导致对DB的不必要的查询,并可能导致列表中的对象重复) 我知道有一种方法可以确保这种加载线程的安全性(只是不确定如何实现)——有

我有一些静态字典对象,它为我保存了一些常量列表,这样我就不必每次加载网站时都从数据库中加载它们(例如:国家列表、类别列表)

因此,我有一个静态函数,它检查实例是否为null,如果为null,则查询数据库,实例化静态变量,并用数据填充它

由于它是一个网站,因此可能会有一种情况,即当对象为空时,多人同时尝试访问该信息,所有这样做的人都会同时调用该进程(这实际上是不必要的,会导致对DB的不必要的查询,并可能导致列表中的对象重复)

我知道有一种方法可以确保这种加载线程的安全性(只是不确定如何实现)——有人能给我指出正确的方向吗?我应该用锁吗

谢谢

更新II:

这就是我写的(这是一个好的线程安全代码吗?)

private static Lazy\u countries=new Lazy(loadCountries);
私有静态列表加载国家()
{
列表结果=新列表();
DataTable dtCountries=SqlHelper.ExecuteDataTable(“stp_Data_Countries_Get”);
foreach(dtCountries.Rows中的数据行dr)
{
结果。添加(新国家/地区)
{
ID=Convert.ToInt32(dr[“CountryId”]),
Name=dr[“Name”].ToString()
});
}
返回结果;
}
公共静态列表GetAllCountries()
{
返回值_.Value;
}

如果您使用的是.NET 4.0,则可以使用内置的惰性泛型类

private static Lazy<YourObject> data = new Lazy<YourObject>(YourInitializationFunction);
public static YourObject Data { get { return data.Value; } }
您可以使用以惰性和线程安全的方式加载资源:

Lazy<List<string>> countries = 
    new Lazy<List<string>>(()=> /* get your countries from db */);
懒惰国家=
新懒人(()=>/*从db*/)获取您的国家/地区;
更新:

public static class HelperTables
{
   private static Lazy<List<ICountry>> _countries;

   static HelperTables //Static constructor
   {
       //Instantiating the lazy object in the static constructor will prevent race conditions
      _countries = new Lazy<List<ICountry>>(() =>
      {
        List<ICountry> result = new List<ICountry>();

        DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
        foreach (DataRow dr in dtCountries.Rows)
        {
            result.Add(new Country
            {
                ID = Convert.ToInt32(dr["CountryId"]),
                Name = dr["Name"].ToString()
            });
        }

        return result;
      });
   }

   public static List<ICountry> GetAllCountries()
   {
      return _countries.Value;
   }
}
公共静态类HelperTables
{
私营部门(国家);;
静态HelperTables//静态构造函数
{
//在静态构造函数中实例化惰性对象将防止竞争条件
_国家=新的懒惰(()=>
{
列表结果=新列表();
DataTable dtCountries=SqlHelper.ExecuteDataTable(“stp_Data_Countries_Get”);
foreach(dtCountries.Rows中的数据行dr)
{
结果。添加(新国家/地区)
{
ID=Convert.ToInt32(dr[“CountryId”]),
Name=dr[“Name”].ToString()
});
}
返回结果;
});
}
公共静态列表GetAllCountries()
{
返回值_.Value;
}
}

@BRAHIMKamel:是的。线程安全模式的默认值是ExecutionAndPublication,实际上,它是使用显式锁的版本。确定,但不应在其中向collection@BRAHIMKamel:是的,但那不是问题的一部分。OP要求提供一种从数据库安全初始化常量列表的方法。他可以通过任意方式实现YourInitialization函数来实现这一点。在安全加载数据后操作数据是完全不同的事情,而不是OP要求的。嗨,请查看我上面的更新-这是一个好的线程安全代码吗?还是我在这里跑偏了?谢谢:)不,不是这个。必须将构造函数权限添加到字段声明中。然后在Get*方法中,只返回countries.Value,它将为您处理线程安全初始化:)他们写道:“使惰性对象线程安全不会保护惰性初始化的对象。如果多个线程可以访问惰性初始化的对象,则必须使其属性和方法对多线程访问安全。”您能解释一下吗?@developer82这意味着您必须自己处理
Lazy
返回对象的线程安全性。在这种情况下,例如,返回的
列表
实例不是线程安全的,只有它的构造和初始化受Lazy的保护。@Alberto从页面中的示例中,我看到它们确实使用了lock关键字-这是否意味着我需要在任何情况下使用该关键字?我只需要一个线程初始化它?@developer82否。在该示例中,锁用于同步对对象(LargeObject)的访问在它被
Lazy
初始化之后,您好,请查看我上面的更新-这是一个好的线程安全代码吗?还是我在这里跑偏了?谢谢:)关于您的更新:如果延迟加载代码抛出,异常将由延迟对象存储,并始终重试。然后对应用程序进行冲洗,直到重新启动。
Lazy<List<string>> countries = 
    new Lazy<List<string>>(()=> /* get your countries from db */);
public static class HelperTables
{
   private static Lazy<List<ICountry>> _countries;

   static HelperTables //Static constructor
   {
       //Instantiating the lazy object in the static constructor will prevent race conditions
      _countries = new Lazy<List<ICountry>>(() =>
      {
        List<ICountry> result = new List<ICountry>();

        DataTable dtCountries = SqlHelper.ExecuteDataTable("stp_Data_Countries_Get");
        foreach (DataRow dr in dtCountries.Rows)
        {
            result.Add(new Country
            {
                ID = Convert.ToInt32(dr["CountryId"]),
                Name = dr["Name"].ToString()
            });
        }

        return result;
      });
   }

   public static List<ICountry> GetAllCountries()
   {
      return _countries.Value;
   }
}