C#比赛条件处理
虽然我意识到有很多这样的问题,但我找不到具体适用于我的案例的东西。所以我想我会冒着复制的风险来得到我问题的答案 背景信息: 我有一个主对象(ActionsMaster),它包含一系列子对象作为属性并处理高级方法。我的“处理表单”将处理将此列表中的每个操作应用到环境中的代码,但由于应用操作的调用可以是多线程的/一次支持多个调用,我认为我将是高效的,一次生成大约5或10个线程(想想这里的数千个操作…我希望这是快速的) 因此,为了支持这一点,我在我的子对象类型中添加了一个Status属性,表示它是否已被传递给线程进行操作,或者它是否可以自由使用,以及是否向ActionsMaster添加了一个用于锁定的对象 到目前为止的代码: 下面是我用来确定某个操作是否可用的代码,这就是我的问题的来源:我可以将对象返回到锁块内吗?或者我必须说明,如果我返回锁块,它将永远不会到达锁块的末尾吗?我需要在运行LINQ语句之前锁定,否则两个线程可能会得到相同的结果。。。以下是我所拥有的:C#比赛条件处理,c#,multithreading,race-condition,C#,Multithreading,Race Condition,虽然我意识到有很多这样的问题,但我找不到具体适用于我的案例的东西。所以我想我会冒着复制的风险来得到我问题的答案 背景信息: 我有一个主对象(ActionsMaster),它包含一系列子对象作为属性并处理高级方法。我的“处理表单”将处理将此列表中的每个操作应用到环境中的代码,但由于应用操作的调用可以是多线程的/一次支持多个调用,我认为我将是高效的,一次生成大约5或10个线程(想想这里的数千个操作…我希望这是快速的) 因此,为了支持这一点,我在我的子对象类型中添加了一个Status属性,表示它是否已
internal ActionFileAction GetNextFreeAction()
{
lock (_IsLocked)
{
ActionFileAction action = this.Actions.DefaultIfEmpty(null).FirstOrDefault(a => a.Status == null || a.Status == Action_Status.Free);
if (action != null)
action.Status = Action_Status.Queued;
return action;
}
}
我会在后台工作人员中这样称呼它:
void bkg_Automatic_DoWork(object sender, DoWorkEventArgs e)
{
//check for user cancel...
if (this.CancelJobs || this.IsAbort)
{
e.Cancel = true;
}
else
{
if (!this.IsFinished)
{
ActionFileAction action = this.TheFile.GetNextFreeAction();
if (action == null)
{
this.IsFinished = true;
}
else
{
//PROCESS THE ACTION HERE...
}
}
}
e.Result = true;
}
下面是我的RunWorkerCompleted代码:
void bkg_Automatic_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
if (e.Cancelled)
{
GenericLogEntry ent = new GenericLogEntry();
ent = new GenericLogEntry();
ent.Area = "SYSTEM";
ent.Action = "USER ABORT";
ent.Description = this.CancelJobs == true ? "CLOSED FORM" : "PUSHED ABORT BUTTON";
ent.Stamp = DateTime.Now;
ent.Status = LogEntryStatus.Fail;
UpdateLogView(ent);
}
else
{
if (this.IsFinished)
{
//add all processed actions to the deployment results, if not already done.
}
else
{
//spawn new thread from this one's END...
BackgroundWorker bkg1 = new BackgroundWorker();
bkg1.DoWork += new DoWorkEventHandler(bkg_Automatic_DoWork);
bkg1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(bkg_Automatic_RunWorkerCompleted);
bkg1.WorkerSupportsCancellation = true;
bkg1.RunWorkerAsync();
}
}
}
这是实现我想要实现的目标的正确方法吗?是.Net framework的v4版本,它将为您处理所有这些问题。学习如何使用它会有一点开销,但最终我认为你会更喜欢学习一个经过尝试、测试和标准的库,而不是花时间自己制作
基本上,您可以将任务交给it来执行,it将处理对它们进行排队并在池中的线程上运行它们的问题
关于使用TPL,尽管其中的代码不是很清楚。
这可能更清楚。将工作转移到多个线程并不总是解决办法。 当试图将工作移到后台线程时,应始终考虑您的机器有多少内核。在一台有2个内核的机器上启动5-10个线程将导致大量上下文切换,这可能会降低代码的性能 现在,我们来看看解决方案。如果您的目标是.NET4.0或更高版本,我建议您使用ConcurrentQueue和TPL的组合。您的代码可以如下所示:
private ConcurrentQueue<ActionFileAction> _actionFileQueue = new ConcurrentQueue<ActionFileAction>();
internal ActionFileAction GetNextFreeAction(CancellationToken cancellationToken = default(CancellationToken))
{
// Checks if a cancellation was requested
cancellationToken.ThrowIfCancellationRequested();
ActionFileAction actionFileToHandle;
_actionFileQueue.TryDequeue(out actionFileToHandle);
//may return null if couldn't dequeue
return actionFileToHandle;
}
//C# Methods should be CamelCase without underscores
void HandleAllActionFiles()
{
try
{
var cancellationToken = new CancellationTokenSource().Token;
Parallel.Invoke(
new ParallelOptions
{
MaxDegreeOfParallelism = Environment.ProcessorCount,
CancellationToken = cancellationToken
}, () => GetNextFreeAction());
}
catch (OperationCanceledException e)
{
// Do stuff with cancellation
}
}
private ConcurrentQueue\u actionFileQueue=new ConcurrentQueue();
内部操作FileAction GetNextFreeAction(CancellationToken CancellationToken=default(CancellationToken))
{
//检查是否请求取消
cancellationToken.ThrowIfCancellationRequested();
ActionFileActionFileToHandle;
_TryDequeue(out actionFileToHandle);
//如果无法退出队列,则可能返回null
返回actionFileToHandle;
}
//C#方法应为不带下划线的大小写
void HandleAllActionFiles()
{
尝试
{
var cancellationToken=新的CancellationTokenSource().Token;
并行调用(
新的并行选项
{
MaxDegreeOfParallelism=Environment.ProcessorCount,
CancellationToken=CancellationToken
},()=>GetNextFreeAction());
}
捕捉(操作取消异常e)
{
//做些取消的事情
}
}
当然,您仍然需要处理retrys并不断地倾听队列以查看是否有项目正在等待,但这可以让您开始:)简而言之,不是。您正在为每个操作创建一个新线程。您应该重新使用线程,而不是不断地拆下它们并创建新的线程,因为这些操作非常昂贵。有一些工具/库可以为您处理这些类型的事情。您希望使用线程池(不需要自己为线程池编写代码)。您的队列在实现上也非常低效,但从您所展示的情况来看,它并不是不安全的。您能否提供一些示例,说明正确的方法是什么?基本上,我希望一次运行10个线程,并且希望,是的,重复使用相同的线程/内存中已有的后台工作线程来应用下一个操作。我明白你的意思,但我不知道如何重新使用内存,只是代码块。。。如果您也有关于如何构建一个高效队列的示例,而这不是我所做的,请提供我认为使用泛型有效的示例…--那么,在lock()块中返回对象不会引起问题吗?不,对于这个网站来说,这个主题太宽泛了。坐下来看书,上课,或者阅读一些相关的教程/博客/文章。@Servy:使用默认同步提供程序的对象是否依赖于
线程池而不是每次生成新线程?我真的很想知道在Lock()块中返回我的对象是否会导致问题。。。但这也很好。谢谢不,这不会引起问题。当您离开锁块的作用域时,锁将被释放,无论您如何离开。我认为在封面下,lock语句基本上是一个try…finally块,它执行一个监视器。在try和Monitor之后输入(o)。在finally中退出(o)。顺便说一句,你是对的:我尝试使用自己的后台工作人员运行代码,实际上它比我一个接一个地运行操作时慢。。。真奇怪@MaxOvrdrv在分配新线程时,操作系统会执行一系列工作,例如分配新堆栈、设置新线程上下文、新Thr