所以我正在运行查询并使用名为 StartJob 的函数处理并行返回的行,这些函数将在我的作业上运行:
ThreadPool.QueueUserWorkItem(StartJob, job);
效果很好而且非常快。但现在我被告知,当查询返回时,某些行可能具有相同的job.UserID值,并且我们无法同时为job.UserID的相同值运行StartJob函数。问题是:在具有相同UserID的StartJob的任何其他实例完成之前,我怎样才能执行StartJob块?
我确信有一种方法可以获得每个UserID锁,但我不知道该怎么做。谢谢你的帮助。
答案 0 :(得分:1)
HashSet<int> hs = new HashSet<int>(); // In common with all the threads
int id = 1; // Your id
// This is the body of your Thread. You pass it the id as you want.
// A closure on it, or as a parameter of the thread.
// This will begin with short spins, every time trying to add the id to the hashset.
// SpinUntil stops when the lambda function returns true.
SpinWait.SpinUntil(() =>
{
lock (cd)
{
return hs.Add(id);
}
});
// OR, if you know the operation is slow, or < .NET 4.0
// This is clearer. The thread yields until it can add the id to the hashset.
while (true)
{
lock (hs)
{
if (hs.Add(id))
{
break;
}
}
Thread.Yield();
}
// End of the variant
// Remember the try/finally! It's important in case of exceptions!!!
try
{
// Put here your code
// Put here your code
// Put here your code
}
finally
{
lock (hs)
{
hs.Remove(id);
}
}
两个版本,一个适用于短StartJob
,仅适用于.NET 4.0,适用于.NET&gt; = 3.5。
显然hs
在所有主题之间是共同的,id
是job.UserID
。
我将在.NET 4.0下添加,您可以使用SpinLock
代替lock
。它快一点,但它的语法有点棘手。
答案 1 :(得分:1)
使用任务并行库
var tasks = new Dictionary<int, Task>();
QueueJob(Job job)
{
lock(tasks)
if (tasks.ContainsKey(job.UserID))
{
var newTask = tasks[job.UserID].ContinueWith(_=>StartJob(job));
tasks[job.UserID] = newTask;
}
else
tasks[job.UserID] = Task.Factory.StartNew(()=>StartJob(job));
}