C# 服务中的线程安全设置为ConcurrencyMode.Multiple 我正在开发一个WCF应用程序,它正在为许多客户端提供一个自定义对象来访问。它基本上可以工作,但因为我需要处理数千个并发客户端,所以我需要该服务来处理并发读取调用(更新将很少)。我通过在更新对象时锁定私有字段,增加了一些线程安全性 [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); } } } } [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple] 公共密封类TestServerConfig:ConfigBase,ITestInterface { 私有对象updateLock=新对象(); 私有分类列表日期=新分类列表(); 公共日期时间GetDate(字符串键) { 如果(此日期包含项(键)) { 返回此。日期[键]; } 其他的 { return DateTime.MinValue; } } public void SetDate(字符串键,DateTime expirationDate) { 锁(this.updateLock) { 如果(此日期包含项(键)) { 此.dates[键]=到期日期; } 其他的 { this.dates.Add(键,expirationDate); } } } }
我的问题是如何在不锁定的情况下使GetDate线程安全,这样可以执行对GetDate的并发调用,但在检查后但在读取值之前删除集合中的值时,不会随机发生异常 捕获异常并处理它是可能的,但我更愿意继续处理它C# 服务中的线程安全设置为ConcurrencyMode.Multiple 我正在开发一个WCF应用程序,它正在为许多客户端提供一个自定义对象来访问。它基本上可以工作,但因为我需要处理数千个并发客户端,所以我需要该服务来处理并发读取调用(更新将很少)。我通过在更新对象时锁定私有字段,增加了一些线程安全性 [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); } } } } [ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple] 公共密封类TestServerConfig:ConfigBase,ITestInterface { 私有对象updateLock=新对象(); 私有分类列表日期=新分类列表(); 公共日期时间GetDate(字符串键) { 如果(此日期包含项(键)) { 返回此。日期[键]; } 其他的 { return DateTime.MinValue; } } public void SetDate(字符串键,DateTime expirationDate) { 锁(this.updateLock) { 如果(此日期包含项(键)) { 此.dates[键]=到期日期; } 其他的 { this.dates.Add(键,expirationDate); } } } },c#,multithreading,wcf,C#,Multithreading,Wcf,我的问题是如何在不锁定的情况下使GetDate线程安全,这样可以执行对GetDate的并发调用,但在检查后但在读取值之前删除集合中的值时,不会随机发生异常 捕获异常并处理它是可能的,但我更愿意继续处理它 有什么想法吗?我建议您使用ReaderWriterLockSlim文档提供的示例几乎正是您想要的。() 但是,像这样的事情: public DateTime GetDate(string key) { cacheLock.EnterReadLock(); try {
有什么想法吗?我建议您使用
ReaderWriterLockSlim
文档提供的示例几乎正是您想要的。()
但是,像这样的事情:
public DateTime GetDate(string key)
{
cacheLock.EnterReadLock();
try
{
if (this.dates.ContainsKey(key))
{
return this.dates[key];
}
else
{
return DateTime.MinValue;
}
}
finally
{
cacheLock.ExitReadLock();
}
}
public void SetDate(string key, DateTime expirationDate)
{
cacheLock.EnterWriteLock();
try
{
if (this.dates.ContainsKey(key))
{
this.dates[key] = expirationDate;
}
else
{
this.dates.Add(key, expirationDate);
}
}
finally
{
cacheLock.ExitWriteLock();
}
}
readerwriterlocksim
比使用lock
性能好得多,并区分读取和写入,因此,如果没有写入操作发生,则读取将变为非阻塞。我建议您使用ReaderWriterLockSlim
文档提供的示例几乎正是您想要的。()
但是,像这样的事情:
public DateTime GetDate(string key)
{
cacheLock.EnterReadLock();
try
{
if (this.dates.ContainsKey(key))
{
return this.dates[key];
}
else
{
return DateTime.MinValue;
}
}
finally
{
cacheLock.ExitReadLock();
}
}
public void SetDate(string key, DateTime expirationDate)
{
cacheLock.EnterWriteLock();
try
{
if (this.dates.ContainsKey(key))
{
this.dates[key] = expirationDate;
}
else
{
this.dates.Add(key, expirationDate);
}
}
finally
{
cacheLock.ExitWriteLock();
}
}
ReaderWriterLockSlim
比使用锁的性能好得多,并且区分读取和写入,因此如果没有写入,则读取变为非阻塞。有一个专门为此设计的锁(如果使用的是.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();
}
}
}
lockCount
等于构造函数中设置的concurrencyLevel
。有一个专门为此设计的锁(如果您使用的是.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();
}
}
}
lockCount
等于构造函数中设置的concurrencyLevel
。如果您确实负担不起读取锁定,您可以(在锁内)复制列表,相应地更新它,然后替换旧列表。现在可能发生的最糟糕的事情是,一些读数可能有点过时,但它们永远不应该被丢弃
lock (this.updateLock)
{
var temp = <copy list here>
if (temp.ContainsKey(key))
{
temp[key] = expirationDate;
}
else
{
temp.Add(key, expirationDate);
}
this.dates = temp;
}
lock(this.updateLock)
{
变量温度=
if(温度容器箱(钥匙))
{
temp[键]=到期日期;
}
其他的
{
临时添加(键,过期日期);
}
这个日期=温度;
}
效率不是很高,但如果不经常这样做,这可能无关紧要。如果您确实负担不起读取的锁定,您可以(在锁内),复制列表,相应地更新它,然后替换旧列表。现在可能发生的最糟糕的事情是,一些读数可能有点过时,但它们永远不应该被丢弃
lock (this.updateLock)
{
var temp = <copy list here>
if (temp.ContainsKey(key))
{
temp[key] = expirationDate;
}
else
{
temp.Add(key, expirationDate);
}
this.dates = temp;
}
lock(this.updateLock)
{
变量温度=
if(温度容器箱(钥匙))
{
temp[键]=到期日期;
}
其他的
{
临时添加(键,过期日期);
}
这个日期=温度;
}
效率不是很高,但如果你不经常这样做,这可能无关紧要。我也遇到过同样的情况,使用ReaderWriterLockSlim并在这种情况下工作。我也遇到过同样的情况,使用ReaderWriterLockSlim并在这种情况下工作。定义“锁定”吗?你的意思是不使用锁(对象)
?(或Monitor.Enter/Exit
)基本上我想避免任何进程/代码/锁/任何限制GetDate在任何时候在单个线程上执行的东西。简单的回答是,你不能。测试一个值是否存在并获取该值的行为不是原子性的——您必须使该过程相对于它的更新显示为原子性的。这听起来像是System.Threading.ReaderWriterLockSlim
的一个经典用例。您是否必须使用SortedList
,字典是否可以替代?如果是的话,可能会有一个。定义“锁定”吗?你的意思是不使用锁(对象)
?(或Monitor.Enter/Exit
)基本上我想避免任何进程/代码/锁/任何限制GetDate在任何时候在单个线程上执行的东西。简单的回答是,你不能。测试一个值是否存在并获取该值的行为不是原子性的——您必须使该过程相对于它的更新显示为原子性的。这听起来像是System.Threading.ReaderWriterLockSlim
的一个经典用例。您是否必须使用SortedList
,字典是否可以替代?如果是这样的话,.ReaderWriterLock就是专为这种情况设计的,它的性能要好得多。这将是一种对GC征税的好方法,更不用说让WCF接口随着时间的推移而增加响应时间了。。。这两种方法都不是很好,特别是当出于性能原因需要避免使用lock
时。@Scot