任务和全局变量c#

时间:2014-09-24 14:05:20

标签: c# wpf scheduled-tasks

我有一个由事件处理程序启动的函数。在此函数中,创建一个新任务并运行以设置一个全局变量,稍后我将在另一个事件处理程序中设置该变量。

这两者之间还有一些其他功能,它们不会改变这些中使用的任何变量。但这就是它的样子。

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);
}

我遇到竞争条件,我需要_variableIneed的变量在第二个事件处理程序中为空,而不是。如果我没有飞过并尝试创建足够的事件来破坏wpf程序,它工作正常,但即使我这样做,我也需要它工作。

我能做些什么来克服这些竞争条件吗?

我尝试使用.ContinueWith选项OnlyOnRanToCompletion或其他任何内容。我可以尝试其他任何事情吗?

**注意我不能通过改变事件的排序/处理/工作方式来做很多事情。这是一个非常漂亮的石头设计,我只需要解决它并保持它或多或少的方式。

**更新

我也尝试将ParallelExtensionsExtrasOrderedTaskScheduler类一起使用,我仍然最终得到了我需要的变量的空引用。

2 个答案:

答案 0 :(得分:3)

当您有Task生成值时,不要将结果设置为全局变量,请将该结果作为任务的Result,并存储该任务。当稍后某些其他代码需要该结果时,它可以从任务中获取它。这将允许Task类处理所有复杂的同步逻辑,防止在任务实际计算结果之前使用结果等。

当然,对于需要使用结果的事件,它可能不需要阻止该任务,而是在任务完成后异步执行需要结果的其余代码。通过在该任务上使用await,可以非常轻松地完成此操作。如果您只使用.NET 4.0,那么您可以明确地使用ContinueWith

答案 1 :(得分:1)

使用Servy的方法 - 异步/任务。此答案仅用于娱乐目的,或者如果您不能使用.Net 4.0+或3.5 with Rx


由于您无法更改事件的顺序,因此您需要不时期望该变量为null,或者阻止该变量被视为null

一个选项是轮询此变量,只有在未设置为null时才能正常工作(如果EventWhereINeedTheGlobalVariableLater没有反复触发,可能需要定时器。)

或者,您可以始终在变量中保留值,或者阻止其他线程看到null值。

防止null在成功的情况下可见,如果"长计算"仍然可以为null。失败:

   object lockObj = new object(); // at class level

   private void EventWhereISetGlobalVariable ...
   {
     lock(lockObj)
     {
       _variableIneed = null;
       // some long and convoluted computations
       _variableIneed = someResult;
     }
   }

   private void EventWhereINeedTheGlobalVariableLater(object sender, Event e)
   {
     lock(lockObj)
     {
      // unsing _variableIneed 
     }
   }

通过仅在我们有一个值时设置值来阻止将其设置为null(锁定对变量的访问权限或volatile将起作用,更喜欢在其他样本中锁定)。这是用于缓存一些需要很长时间计算的值的常见模式,如果变量的用户看到稍微陈旧的值,则可以。

   volatile WhateverYourType _variableIneed;
   private void EventWhereISetGlobalVariable ...
   {
       // some long and convoluted computations
       _variableIneed = someResult ?? _variableIneed;
   }

注意:

  • 确保您了解如何处理代码中的任何锁定/同步 - 因此请务必在多个位置使用该变量。考虑使用lock包装对变量的访问。
  • 考虑将值复制到锁内的局部变量,并在代码中使用局部变量,并且需要值"。否则其他线程可能会将其更改为新值/ null。
  • 对于一次性设置变量,请考虑处理此类初始化的Lazy<T>类,或者使用Cache来存储值更合适。