C#并发字典对象读取/更新线程安全问题
在下面的代码中,我有一个并发字典,用于存储单个键/值对,其中值是字符串的集合 我将从不同的线程读取和更新这个单一键/值对中的字符串 我知道,如果一个线程在另一个线程可能完成读取之前更改了一个值,那么并发字典并不是完全线程安全的。但同样地,我也不确定字符串值是否真的会出现在这个话题中,是否有人能提出建议 还值得一提的是,尽管我将这个“GetRunTimeVariables”方法放入了一个依赖注入接口,但实际上我不能一直使用DI来访问这个方法,因为在应用程序启动和OIDC事件登录/注销的阶段,我需要访问不能使用依赖注入的类中的字典值,因此,本质上,我可以在应用程序的整个生命周期中,根据需要从nay-means访问此词典 最后,我不确定将这个方法推广到一个接口中是否有任何好处,另一个选项只是在每次我需要它的时候更新对这个类的引用,对此的一些想法将不胜感激C#并发字典对象读取/更新线程安全问题,c#,.net-core,concurrentdictionary,C#,.net Core,Concurrentdictionary,在下面的代码中,我有一个并发字典,用于存储单个键/值对,其中值是字符串的集合 我将从不同的线程读取和更新这个单一键/值对中的字符串 我知道,如果一个线程在另一个线程可能完成读取之前更改了一个值,那么并发字典并不是完全线程安全的。但同样地,我也不确定字符串值是否真的会出现在这个话题中,是否有人能提出建议 还值得一提的是,尽管我将这个“GetRunTimeVariables”方法放入了一个依赖注入接口,但实际上我不能一直使用DI来访问这个方法,因为在应用程序启动和OIDC事件登录/注销的阶段,我需要
public class RunTimeSettings : IRunTimeSettings
{
// Create a new static instance of the RunTimeSettingsDictionary that is used for storing settings that are used for quick
// access during the life time of the application. Various other classes/threads will read/update the parameters.
public static readonly ConcurrentDictionary<int, RunTimeVariables> RunTimeSettingsDictionary = new ConcurrentDictionary<int, RunTimeVariables>();
public object GetRunTimeVariables()
{
dynamic settings = new RunTimeVariables();
if (RunTimeSettingsDictionary.TryGetValue(1, out RunTimeVariables runTimeVariables))
{
settings.Sitename = runTimeVariables.SiteName;
settings.Street = runTimeVariables.Street;
settings.City = runTimeVariables.City;
settings.Country = runTimeVariables.Country;
settings.PostCode = runTimeVariables.PostCode;
settings.Latitude = runTimeVariables.Latitude;
settings.Longitude = runTimeVariables.Longitude;
}
return settings;
}
}
System.String
类型(C#的经典String
s)是不可变的。任何人都不能修改字符串的“内容”。任何人都可以将属性引用设置为不同的字符串
但事实上,这里唯一的问题是各种值可能会被取消同步。您有各种相关的属性。如果一个线程正在修改对象,而另一个线程正在读取它,那么读取线程可能会看到“旧”版本的一些属性和“新”版本的一些属性。如果对象一旦写入ConcurrentDictionary
后没有更改(至少作为业务规则是“不可变的”),那么这不是一个大问题。显然,正确的解决方案是将运行时变量
设置为不可变对象(例如,仅由在实例化时初始化的只读
字段组成)系统。字符串
类型(C#的经典字符串
s)是不可变的。任何人都不能修改字符串的“内容”。任何人都可以将属性引用设置为不同的字符串
但事实上,这里唯一的问题是各种值可能会被取消同步。您有各种相关的属性。如果一个线程正在修改对象,而另一个线程正在读取它,那么读取线程可能会看到“旧”版本的一些属性和“新”版本的一些属性。如果对象一旦写入ConcurrentDictionary
后没有更改(至少作为业务规则是“不可变的”),那么这不是一个大问题。显然,正确的解决方案是将RuntimeVariables
设置为不可变对象(例如,仅由在实例化时初始化的readonly
字段组成)如果我没有弄错的话TryGetValue
不是线程安全的,但它需要更多的研究()有人会认为“尝试做”某件事肯定比说“做某件事”更安全,嗯,我有兴趣了解更多这方面的信息。试图理解官方MS文档很少helps@ipinak ??? 所有这些都是线程安全的。唯一的问题是,如果尝试执行TryGetValue
,失败时执行显式Add
。TryGetValue
的结果仅在检索时有效,不能保证它在检索前一刻或之后一刻有效。如果我没有弄错的话,TryGetValue
不是线程安全的,但它需要更多的调查()有人会认为“尝试做”某件事肯定比说“做某件事”更安全,嗯,我有兴趣了解更多这方面的信息。试图理解官方MS文档很少helps@ipinak ??? 所有这些都是线程安全的。唯一的问题是,如果尝试执行TryGetValue
,失败时执行显式Add
。TryGetValue
的结果仅在检索时有效,不能保证它在检索前一刻或后一刻有效。您好,我不理解您解释的后半部分,但值得一提的是,此字符串值集合仅用于日志记录,因此,如果一个线程与另一个线程之间的值存在瞬时的不一致性,则只会影响1qty日志事务。你认为使用我的界面是没有意义的吗?实际上只需要更少的代码行就可以在需要时更新类。。。thx@OJB1将其放在接口中可以更容易地模拟它进行单元测试,至少对于可单元测试的类,字典的值由单元测试设置很重要,和/或无法从正常来源加载字典的值(可能是因为单元测试无法访问db/到具有这些值的远程服务器)@obj1解释的哪一部分不清楚?从哪个词到哪个词?你的最后一句话,你能举个例子说明我应该做的更正吗?thx@OJB1在C#9.0中,将有一个新特性。如果没有C#9.0,您将使用builder模式,使用可变类(如StringBuilder
),该类具有创建不可变对象的方法(返回字符串的.ToString()
)。对于不可变对象,在您读取对象时,另一个线程不可能更改该对象。如果它想更改对象,它必须创建一个具有新值的新对象,然后在dict中切换对象。嗨,我不理解你解释的后面部分,但值得一提的是,这个字符串值集合只是用于日志记录,所以如果va中有一个瞬间的不一致性
public class RunTimeVariables
{
public bool InstalledLocationConfigured { get; set; }
public string SiteName { get; set; }
public string Street { get; set; }
public string City { get; set; }
public string Country { get; set; }
public string PostCode { get; set; }
public string Latitude { get; set; }
public string Longitude { get; set; }
}