gpt4 book ai didi

c# - 服务中的线程安全设置为 ConcurrencyMode.Multiple

转载 作者:太空宇宙 更新时间:2023-11-03 21:45:07 25 4
gpt4 key购买 nike

我正在开发一个 WCF 应用程序,该应用程序托管一个自定义对象供许多客户端访问。它基本上可以工作,但因为我需要处理数以千计的并发客户端,所以我需要该服务能够处理并发读取调用(更新频率不高)。我通过在更新对象时锁定私有(private)字段来添加一些线程安全。

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public sealed class TestServerConfig : ConfigBase, ITestInterface
{
private object updateLock = new object();

private SortedList<string, DateTime> dates = new SortedList<string, DateTime>();

public DateTime GetDate(string key)
{
if (this.dates.ContainsKey(key))
{
return this.dates[key];
}
else
{
return DateTime.MinValue;
}
}
public void SetDate(string key, DateTime expirationDate)
{
lock (this.updateLock)
{
if (this.dates.ContainsKey(key))
{
this.dates[key] = expirationDate;
}
else
{
this.dates.Add(key, expirationDate);
}
}
}
}

我的问题是如何在不锁定的情况下使 GetDate 线程安全,以便可以执行对 GetDate 的并发调用,但在检查之后但读取值之前从集合中删除值时,不会随机发生异常。

捕获异常并处理它是可能的,但我更愿意保留它。

有什么想法吗?

最佳答案

有专门为此设计的锁,ReaderWriterLockSlim (ReadWriterLock 如果您使用的是低于 .NET 4.0 的版本)

此锁允许并发读取,但会在发生写入时锁定读取(和其他写入)。

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public sealed class TestServerConfig : ConfigBase, ITestInterface
{
private ReaderWriterLockSlim updateLock = new ReaderWriterLockSlim();

private SortedList<string, DateTime> dates = new SortedList<string, DateTime>();


public DateTime GetDate(string key)
{
try
{
this.updateLock.EnterReadLock();
if (this.dates.ContainsKey(key))
{
return this.dates[key];
}
else
{
return DateTime.MinValue;
}
}
finally
{
this.updateLock.ExitReadLock();
}
}
public void SetDate(string key, DateTime expirationDate)
{
try
{
this.updateLock.EnterWriteLock();

if (this.dates.ContainsKey(key))
{
this.dates[key] = expirationDate;
}
else
{
this.dates.Add(key, expirationDate);
}
}
finally
{
this.updateLock.ExitWriteLock();
}
}
}

还有支持超时的锁的“尝试”版本,您只需检查返回的 bool 值,看看您是否拿走了锁。


更新:另一种解决方案是使用 ConcurrentDictionary ,这根本不需要任何锁。 ConcurrentDictionary 在内部使用锁,但它们的生命周期比您可以使用的锁的生命周期短,而且 Microsoft 也有可能使用某种形式的不安全方法来进一步优化它,我不知道他们在内部采用哪种锁。

不过你需要做一些重写以使你的操作原子化

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple)]
public sealed class TestServerConfig : ConfigBase, ITestInterface
{
private ConcurrentDictionary<string, DateTime> dates = new ConcurrentDictionary<string, DateTime>();

public DateTime GetDate(string key)
{
DateTime result;

if (this.dates.TryGetValue(key, out result))
{
return result;
}
else
{
return DateTime.MinValue;
}
}
public void SetDate(string key, DateTime expirationDate)
{
this.dates.AddOrUpdate(key, expirationDate, (usedKey, oldValue) => expirationDate);
}
}

更新 2: 出于好奇,我深入了解 ConcurrentDictionary 做了什么,它所做的只是锁定元素的一组桶,所以如果两个对象也共享相同的哈希桶锁,您只会发生锁争用。

通常有 Environment.ProcessorCount * 4 锁桶,但您可以使用设置 concurrencyLevel 的构造函数手动设置它.

这是它如何决定使用哪个锁

private void GetBucketAndLockNo(int hashcode, out int bucketNo, out int lockNo, int bucketCount, int lockCount)
{
bucketNo = (hashcode & 2147483647) % bucketCount;
lockNo = bucketNo % lockCount;
}

lockCount 等于构造函数中设置的 concurrencyLevel

关于c# - 服务中的线程安全设置为 ConcurrencyMode.Multiple,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17432623/

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