阻止并发访问ThreadPool

时间:2011-10-06 11:36:04

标签: c# multithreading

所以我正在运行查询并使用名为 StartJob 的函数处理并行返回的行,这些函数将在我的作业上运行:

ThreadPool.QueueUserWorkItem(StartJob, job);

效果很好而且非常快。但现在我被告知,当查询返回时,某些行可能具有相同的job.UserID值,并且我们无法同时为job.UserID的相同值运行StartJob函数。问题是:在具有相同UserID的StartJob的任何其他实例完成之前,我怎样才能执行StartJob块?

我确信有一种方法可以获得每个UserID锁,但我不知道该怎么做。谢谢你的帮助。

2 个答案:

答案 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在所有主题之间是共同的,idjob.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));                  
}