這聽起來很像鎖管理器,所以爲什麼不建立一個?
class LockManager<TKey>
{
private Dictionary<TKey, List<EventWaitHandle>> locks =
new Dictionary<TKey, List<EventWaitHandle>>();
private Object syncRoot = new Object();
public void Lock(TKey key)
{
do
{
Monitor.Enter(syncRoot);
List<EventWaitHandle> waiters = null;
if (true == locks.TryGetValue(key, out waiters))
{
// Key is locked, add ourself to waiting list
// Not that this code is not safe under OOM conditions
AutoResetEvent eventLockFree = new AutoResetEvent(false);
waiters.Add(eventLockFree);
Monitor.Exit(syncRoot);
// Now wait for a notification
eventLockFree.WaitOne();
}
else
{
// event is free
waiters = new List<EventWaitHandle>();
locks.Add(key, waiters);
Monitor.Exit(syncRoot);
// we're done
break;
}
} while (true);
}
public void Release(TKey key)
{
List<EventWaitHandle> waiters = null;
lock (syncRoot)
{
if (false == locks.TryGetValue(key, out waiters))
{
Debug.Assert(false, "Releasing a bad lock!");
}
locks.Remove(key);
}
// Notify ALL waiters. Unfair notifications
// are better than FIFO for reasons of lock convoys
foreach (EventWaitHandle waitHandle in waiters)
{
waitHandle.Set();
}
}
}
您使用它之前,您必須鎖定每個值:
class Program
{
class ThreadData
{
public LockManager<int> LockManager { get; set; }
public int[] Work { get; set; }
public AutoResetEvent Done { get; set; }
}
static void Main(string[] args)
{
int[] forA = new int[] {5, 8, 9, 12};
int[] forB = new int[] {7, 8, 9, 13, 14 };
LockManager<int> lockManager = new LockManager<int>();
ThreadData tdA = new ThreadData
{
LockManager = lockManager,
Work = forA,
Done = new AutoResetEvent(false),
};
ThreadData tdB = new ThreadData
{
LockManager = lockManager,
Work = forB,
Done = new AutoResetEvent(false),
};
ThreadPool.QueueUserWorkItem(new WaitCallback(Worker), tdA);
ThreadPool.QueueUserWorkItem(new WaitCallback(Worker), tdB);
WaitHandle.WaitAll(new WaitHandle[] { tdA.Done, tdB.Done });
}
static void Worker(object args)
{
Debug.Assert(args is ThreadData);
ThreadData data = (ThreadData) args;
try
{
foreach (int key in data.Work)
{
data.LockManager.Lock(key);
Console.WriteLine("~{0}: {1}",
Thread.CurrentThread.ManagedThreadId, key);
// simulate the load the set for Key
Thread.Sleep(1000);
}
foreach (int key in data.Work)
{
// Now free they locked keys
data.LockManager.Release(key);
}
}
catch (Exception e)
{
Debug.Write(e);
}
finally
{
data.Done.Set();
}
}
}
你要面對的最大問題將是死鎖。將兩個數組更改爲{5,8,9,7}和{7,8,9,5},您將立即看到我的觀點。
是不可變的值嗎? 加載一個值需要多長時間? – MaLio 2010-02-02 20:03:50
你是說你有一個數據流,因此該流中的每個項目都需要由兩個線程處理?延遲是一個大問題? – Keith 2010-02-02 22:01:27
每個請求都會有自己的號碼,大部分時間都會被緩存,然後不會被請求。請求很貴,這就是我們只需要執行一次的原因。 – pablo 2010-02-02 22:46:20