任务和全局变量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,或者至少是链式任务。@Brett
StartNew
的lambda应该
返回结果,而不是设置另一个变量。然后事件处理程序应该
等待您启动的
任务。抱歉,扔了扳手
   volatile WhateverYourType _variableIneed;
   private void EventWhereISetGlobalVariable ...
   {
       // some long and convoluted computations
       _variableIneed = someResult ?? _variableIneed;
   }