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# 服务中的线程安全设置为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 {

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

捕获异常并处理它是可能的,但我更愿意继续处理它


有什么想法吗?

我建议您使用
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