任务和全局变量c#
我有一个由事件处理程序启动的函数。在这个函数中,将创建并运行一个新任务,以在另一个事件处理程序中设置稍后需要的全局变量 这两个函数之间还有一些其他函数,它们不会改变其中使用的任何变量。但这就是它看起来的样子任务和全局变量c#,c#,wpf,scheduled-tasks,C#,Wpf,Scheduled Tasks,我有一个由事件处理程序启动的函数。在这个函数中,将创建并运行一个新任务,以在另一个事件处理程序中设置稍后需要的全局变量 这两个函数之间还有一些其他函数,它们不会改变其中使用的任何变量。但这就是它看起来的样子 private void EventWhereINeedTheGlobalVariableLater(object sender, Event e) { //...work... need _variableIneed //....more work... }
private void EventWhereINeedTheGlobalVariableLater(object sender, Event e)
{
//...work...
need _variableIneed
//....more work...
}
private void EventWhereISetGlobalVariable(object sender, Event e)
{
//....work....
//...make cancellationToken...
//groups, isCommonalityGroup are other global variables already set.
Task.Factory.StartNew(() =>
{
// Clear variable to get new value
_variableIneed = null;
// Execute query to get new value
_variableIneed = _workingManager.GetValue(groups, isCommonalityGroup, cancellationToken);
RefreshView();
}, cancellationToken);
}
我遇到了竞争条件,我需要的变量\u variableed
在第二个事件处理程序中为null,不能为null。如果我没有快速通过并尝试创建足够的事件来崩溃wpf程序,那么它可以正常工作,但是即使我这样做了,我也需要它工作
我能做些什么来克服这些比赛条件吗
我尝试过使用.ContinueWith
,选择onlyon或tocompletion
或其他选项。还有什么我可以试试的吗
**注意,我无法改变事件的排序/处理/处理方式。这是一个很好的石头设计,我只需要围绕它工作,或多或少保持它的原样
**更新
我还尝试将
ParallelExtensionsExtras
与OrderedTaskScheduler
类一起使用,但最终还是得到了所需变量的空引用 使用Servy的方法-异步/任务。此答案仅用于娱乐目的,或者如果您不能使用.Net 4.0+或
由于无法更改事件顺序,因此您需要期望变量不时为
null
,或者防止它被视为null
一个选项是轮询此变量,并且仅在未将其设置为null
时才执行操作(如果您的事件发生在GlobalVariableLater
未重复触发,则可能需要计时器)
或者,您可以始终将值保留在变量中,或者防止其他线程看到null
值
在成功的情况下防止null可见,如果“长计算”失败,仍然可能为null:
当我们有一个变量时,仅通过设置值来防止将其设置为null
(锁定变量访问权限或volatile
都可以,更喜欢像其他示例中那样锁定)。这是缓存一些需要很长时间计算的值的常见模式,如果变量的用户看到稍微过时的值,这是正常的
volatile WhateverYourType _variableIneed;
private void EventWhereISetGlobalVariable ...
{
// some long and convoluted computations
_variableIneed = someResult ?? _variableIneed;
}
注:
- 确保您了解如何处理代码中的任何锁定/同步,因此在多个位置使用该变量时要非常小心。考虑用锁包装对变量的访问。
- 考虑将值复制到锁内的局部变量,并在“需要值”的代码中使用局部变量。否则,其他线程可能会将其更改为新值/null
- 对于一次性设置变量,请考虑<代码>懒惰< /代码>类,用于处理这种初始化,或者如果使用<代码> Cache < /Cord>存储值更合适。
任务
来生成一个值时,不要将结果设置为全局变量,让该结果成为任务的结果
,并存储该任务。当其他代码稍后需要该结果时,它可以从任务中获得该结果。这将允许Task
类处理所有复杂的同步逻辑,防止在任务实际计算结果之前使用结果,等等
当然,对于需要使用结果的事件,它可能不需要阻塞该任务,而是在任务完成后异步执行需要结果的其余代码。在该任务上使用
wait
可以非常轻松地完成此任务。如果您只使用.NET 4.0,则可以显式地使用ContinueWith
。如果在eventwhereitedGlobalVariableLater
处理程序中设置变量之前调用EventWhereISetGlobalVariable
处理程序,则无法执行任何操作。您的意思是说在EventWhereISetGlobalVariable
处理程序中设置变量之前调用处理程序全局变量以后在哪里发生的事件
?可能是任务
未完成?您需要对其进行同步。是@SriramSakthivel我为所需的全局变量获取一个空值。这意味着未调用ISetGlobalVariable的事件或由StartNew创建的任务尚未完成。您可能需要调用任务。等待
或等待
或继续
以同步访问。但在访问它之前,仍然可能存在争用(另一个任务已启动并将\u variableIneed
设置为null)。@srramsakthivel“可能存在争用(另一个任务已启动并已设置…)这就是正在发生的事情。我能做些什么来解决这个问题吗?我试图避免使用任务。如果可能的话,请等待。我有一个问题-为一个变量设置一个锁是否有意义,它将被并行使用?我的意思是,如果我想从另一个线程获取或设置这个变量,它将被锁定TPL是按特别是为了避免要求您这样做,因为它们会增加代码的复杂性、可能出现错误等。考虑到他已经在使用TPL,这不是解决此问题的有效方法。@Sasha lock阻止多个线程运行使用同一锁包装的代码-因此其他线程将等待NE和唯一的胎面留下的是“<代码>锁”的包。这将保证在当前使用/设置/计算它时,其他线程不能改变值。考虑读取和。这样的结果是什么,结果是任务的<代码>结果< /代码>,然后从任务中访问它?+ 1。使用4.5和c。ode>async
code,或者至少是链式任务。@BrettStartNew
的lambda应该返回结果,而不是设置另一个变量。然后事件处理程序应该等待您启动的任务。抱歉,扔了扳手
volatile WhateverYourType _variableIneed;
private void EventWhereISetGlobalVariable ...
{
// some long and convoluted computations
_variableIneed = someResult ?? _variableIneed;
}