gpt4 book ai didi

c# - 在私有(private)字段中使用 Bcl ImmutableDictionary

转载 作者:太空狗 更新时间:2023-10-29 22:27:08 26 4
gpt4 key购买 nike

假设我有一个将从多个线程调用的类,并且我打算将一些数据存储在 ImmutableDictionary 中。在这个类的私有(private)字段中

public class Something {
private ImmutableDictionary<string,string> _dict;
public Something() {
_dict = ImmutableDictionary<string,string>.Empty;
}

public void Add(string key, string value) {

if(!_dict.ContainsKey(key)) {
_dict = _dict.Add(key,value);
}
}
}

这会不会被多个线程以这样一种方式调用,以至于您会得到关于字典中已经存在的键的错误?

Thread1 检查字典发现 falseThread2 检查字典是否为假Thread1 添加值并更新对 _dict 的引用Thread2 增加了值,但它已经被添加了,因为它使用了相同的引用?

最佳答案

在使用不可变字典时,您绝对可以做到线程安全。数据结构本身是完全线程安全的,但您在多线程环境中对其应用更改必须小心编写,以避免在您自己的代码中丢失数据。

这是我经常在这种情况下使用的模式。它不需要锁,因为我们所做的唯一改变是单个内存分配。如果必须设置多个字段,则需要使用锁。

using System.Threading;

public class Something {
private ImmutableDictionary<string, string> dict = ImmutableDictionary<string, string>.Empty;

public void Add(string key, string value) {
// It is important that the contents of this loop have no side-effects
// since they can be repeated when a race condition is detected.
do {
var original = _dict;
if (local.ContainsKey(key)) {
return;
}

var changed = original.Add(key,value);
// The while loop condition will try assigning the changed dictionary
// back to the field. If it hasn't changed by another thread in the
// meantime, we assign the field and break out of the loop. But if another
// thread won the race (by changing the field while we were in an
// iteration of this loop), we'll loop and try again.
} while (Interlocked.CompareExchange(ref this.dict, changed, original) != original);
}
}

事实上,我经常使用这种模式,为此我定义了一个静态方法:

/// <summary>
/// Optimistically performs some value transformation based on some field and tries to apply it back to the field,
/// retrying as many times as necessary until no other thread is manipulating the same field.
/// </summary>
/// <typeparam name="T">The type of data.</typeparam>
/// <param name="hotLocation">The field that may be manipulated by multiple threads.</param>
/// <param name="applyChange">A function that receives the unchanged value and returns the changed value.</param>
public static bool ApplyChangeOptimistically<T>(ref T hotLocation, Func<T, T> applyChange) where T : class
{
Requires.NotNull(applyChange, "applyChange");

bool successful;
do
{
Thread.MemoryBarrier();
T oldValue = hotLocation;
T newValue = applyChange(oldValue);
if (Object.ReferenceEquals(oldValue, newValue))
{
// No change was actually required.
return false;
}

T actualOldValue = Interlocked.CompareExchange<T>(ref hotLocation, newValue, oldValue);
successful = Object.ReferenceEquals(oldValue, actualOldValue);
}
while (!successful);

Thread.MemoryBarrier();
return true;
}

您的 Add 方法会变得更加简单:

public class Something {
private ImmutableDictionary<string, string> dict = ImmutableDictionary<string, string>.Empty;

public void Add(string key, string value) {
ApplyChangeOptimistically(
ref this.dict,
d => d.ContainsKey(key) ? d : d.Add(key, value));
}
}

关于c# - 在私有(private)字段中使用 Bcl ImmutableDictionary,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14655248/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com