多线程中的锁的概念是为了保证原子操作. 所谓的原子操作, 就是说对一个对象的修改需要多个步骤完成,那么我们希望这个修改动作在没有任何外部打断的情况下,从第一步到最后一步能够完整的执行完. 在多线程编程中, 可能有多个线程都会去执行这个修改动作, 那么不同的线程在对同一个对象执行同一个修改动作时, 就有可能发生抢占的行为. 就是说线程 A 的修改动作还没完成, 线程 B 就开始修改动作, 这时候被修改对象的内容就被污染了, 它既不是线程 A 期望的内容, 也不是线程 B 期望的内容. 这时候我们就可以给修改对象加上一个锁, 只有拥有该锁的线程才有资格去执行修改动作, 修改完成后, 别的进程才有机会去执行修改动作.
最简单的锁当然就是互斥锁了, 但是对于读写来说, 可能会有多个线程读一个对象, 而只有一个线程要写这个对象. 那么对于读线程来说, 它不改变对象的内容, 我们就应该允许多个线程同时读, 只有在写的时候才要给锁住对象. 这样可以提高读线程的吞吐量. 以下介绍一个读写锁, 可以用来对 Dictionary 对象来加读写锁, 从而来实现一个同步的 Dictionary.
使用一个ReaderWriterLock来实现一个同步的Cache, 以便控制对该Cache的读写.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
namespace ReadWriteLockSlimTest
{
class SynchronizedCache
{
private ReaderWriterLockSlim cacheLock = new ReaderWriterLockSlim();
private Dictionary<int, string> innerCache = new Dictionary<int, string>();
public string Read(int key)
{
cacheLock.EnterReadLock();
try
{
return innerCache[key];
}
finally
{
cacheLock.ExitReaderLock();
}
}
public void Add(int key, string value)
{
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public bool AddWithTimeout(int key, string value, int timeout)
{
if (cacheLock.TryEnterWriteLock(timeout))
{
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitReaderLock();
}
return true;
}
else
{
return false;
}
}
public AddOrUpdateStatus AddOrUpdate(int key, string value)
{
cacheLock.EnterUpgradeableReadLock();
try
{
string result = null;
if (innerCache.TryGetValue(key, out result))
{
if (result == value)
{
return AddOrUpdateStatus.Unchanged;
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache[key] = value;
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Updated;
}
}
else
{
cacheLock.EnterWriteLock();
try
{
innerCache.Add(key, value);
}
finally
{
cacheLock.ExitWriteLock();
}
return AddOrUpdateStatus.Added;
}
}
finally
{
cacheLock.ExitUpgradeableReadLock();
}
}
public void Delete(int key)
{
cacheLock.EnterWriteLock();
try
{
innerCache.Remove(key);
}
finally
{
cacheLock.ExitWriteLock();
}
}
public enum AddOrUpdateStatus
{
Added,
Updated,
Unchanged
};
}
}