C# 阻止并发访问线程池
因此,我正在运行一个查询并使用一个名为StartJob的函数处理并发返回的行,该函数将用于我的作业:C# 阻止并发访问线程池,c#,multithreading,C#,Multithreading,因此,我正在运行一个查询并使用一个名为StartJob的函数处理并发返回的行,该函数将用于我的作业: ThreadPool.QueueUserWorkItem(StartJob, job); 工作非常好,速度非常快。但是现在我被告知当查询返回时,一些行可能具有相同的job.UserID值,并且我们不能同时为相同的job.UserID值运行StartJob函数。问题是:在具有相同用户ID的StartJob的任何其他实例完成之前,如何执行StartJob块 我确信有一种方法可以获得每个用户ID的锁
ThreadPool.QueueUserWorkItem(StartJob, job);
工作非常好,速度非常快。但是现在我被告知当查询返回时,一些行可能具有相同的job.UserID值,并且我们不能同时为相同的job.UserID值运行StartJob函数。问题是:在具有相同用户ID的StartJob的任何其他实例完成之前,如何执行StartJob块
我确信有一种方法可以获得每个用户ID的锁,但我不知道怎么做。谢谢您的帮助。HashSet hs=new HashSet();//与所有线程相同
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);
}
}
int id=1;//你的身份证
//这是你的线体。你可以根据自己的需要传递id。
//它的闭包,或作为线程的参数。
//这将从短旋转开始,每次尝试将id添加到哈希集中。
//当lambda函数返回true时,SpinUntil停止。
SpinWait.SpinUntil(()=>
{
锁(cd)
{
返回hs.Add(id);
}
});
//或者,如果您知道操作很慢,或者<.NET 4.0
//这更清楚。该线程将在可以将id添加到哈希集之前进行让步。
while(true)
{
锁(hs)
{
如果(hs.添加(id))
{
打破
}
}
螺纹屈服强度();
}
//变体的结尾
//记住试试/最后!这在例外情况下很重要!!!
尝试
{
//把你的密码放在这里
//把你的密码放在这里
//把你的密码放在这里
}
最后
{
锁(hs)
{
hs.移除(id);
}
}
两个版本,一个适合缩写StartJob
,仅适用于.NET 4.0,另一个适用于.NET>=3.5
显然,hs
在所有线程之间是通用的,而id
是job.UserID
我将在.NET4.0下添加,您可以使用
SpinLock
而不是lock
。它有点快,但语法有点复杂。使用任务并行库
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));
}
var tasks=newdictionary();
队列作业(作业作业)
{
锁定(任务)
if(tasks.ContainsKey(job.UserID))
{
var newTask=tasks[job.UserID].ContinueWith(=>StartJob(job));
任务[job.UserID]=newTask;
}
其他的
tasks[job.UserID]=Task.Factory.StartNew(()=>StartJob(job));
}
如果您使用相同的job.UserID运行StartJob,直到它指向某个共享资源(如数据库中的文件或行),将不会出现并发冲突。你能展示一下你在StartJob做什么吗?什么版本的.NET?3.5或4.0?@完全正确,我在StartJob中运行了更多的查询,这些查询会锁定用户ID拥有的行,因此我们会看到超时,因为这些长时间运行的查询会锁定这些行。因此,我想用一些特定于UserID的锁启动StartJob,并在那里阻塞,直到释放为止。如果你必须用相同的id对同一行执行相同的操作,这不是相同的操作吗?我的意思是,为什么你需要多次这样做?也许你只需要删除副本?不是任务。继续,最后一个任务。ContinueWith@xanatos那是不可能的。试试看,对。。。和var newTask=lastTask.ContinueWith(=>StartJob(job))代码>?