我想出了這個天真的實現。
internal class LockingTest
{
private readonly Dictionary<string, ReaderWriterLockSlim> _Locks = new Dictionary<string, ReaderWriterLockSlim>();
private void LockRow (string id)
{
ReaderWriterLockSlim slim;
for (; ;) {
lock (_Locks) {
/*
* if row not in use, grab it
*/
if (!_Locks.TryGetValue (id, out slim)) {
slim = new ReaderWriterLockSlim(); // this can probably be replaced by a different, cheap signal class
slim.EnterWriteLock();
_Locks.Add (id, slim);
return;
}
}
/*
* row is in use, wait until released, then try again
*/
slim.EnterWriteLock();
}
}
private void UnlockRow (string id)
{
/*
* release and remove lock
*/
lock (_Locks) {
var slim = _Locks[id];
_Locks.Remove (id);
slim.ExitWriteLock();
}
}
public void Test()
{
var rnd = new Random();
Action thread =() => {
for (; ;) {
var id = rnd.NextDouble() < 0.5 ? "a" : "b";
Console.WriteLine (Thread.CurrentThread.Name + " waits for " + id);
LockRow (id);
Console.WriteLine (Thread.CurrentThread.Name + " locked " + id);
Thread.Sleep (rnd.Next (0, 100));
UnlockRow (id);
Console.WriteLine (Thread.CurrentThread.Name + " released " + id);
Thread.Sleep (rnd.Next (0, 100));
}
};
new Thread (() => thread()) {
Name = "L1",
IsBackground = true
}.Start();
new Thread (() => thread()) {
Name = "L2",
IsBackground = true
}.Start();
Thread.Sleep (1000);
}
輸出
L1 waits for a
L1 locked a
L2 waits for b
L2 locked b
L2 released b
L1 released a
L1 waits for a
L1 locked a
L2 waits for a
L1 released a
L2 locked a
L2 released a
L1 waits for b
L1 locked b
L2 waits for b
L1 released b
L2 locked b
L1 waits for a
L1 locked a
L2 released b
L1 released a
L1 waits for a
L1 locked a
L2 waits for a
L1 released a
L2 locked a
L1 waits for b
L1 locked b
L1 released b
L2 released a
L1 waits for b
L1 locked b
L1 released b
L2 waits for a
L2 locked a
L2 released a
L1 waits for b
L1 locked b
L2 waits for a
L2 locked a
L2 released a
L1 released b
L1 waits for b
L1 locked b
L1 released b
L2 waits for a
L2 locked a
L1 waits for a
L2 released a
L1 locked a
L2 waits for b
L2 locked b
L1 released a
L1 waits for b
L2 released b
L1 locked b
L1 released b
更新的源代碼,包括除了本地鎖全局鎖看到https://github.com/mafutrct/Zysl/blob/master/trunk/Zysl/Utils/BlockingSet。 CS – mafu 2012-03-16 15:10:30