任务和全局变量c#

本文关键字:全局变量 任务 | 更新日期: 2023-09-27 18:24:09

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

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

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在第二个事件处理程序中为null,但它不可能为null。如果我没有快速通过并试图创建足够的事件来破坏wpf程序,它会很好地工作,但即使我这样做了,我也需要它工作。

我能做些什么来克服这些比赛条件吗?

我试过使用.ContinueWithOnlyOnRanToCompletion或其他什么选项。我还可以尝试其他东西吗?

**请注意,我无法更改事件的排序/处理/处理方式。这是一个漂亮的石头设计,我只需要围绕它工作,并或多或少地保持原样。

**更新

我还尝试过将ParallelExtensionsExtrasOrderedTaskScheduler类一起使用,但最终还是得到了对所需变量的null引用。

任务和全局变量c#

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

当然,对于需要使用结果的事件,它可能不需要阻塞该任务,而是在任务完成后异步执行需要结果的代码的其余部分。这可以通过在该任务中使用await来非常容易地完成。如果您只使用.NET 4.0,则可以显式使用ContinueWith

使用Servy的方法-async/Tasks。这个答案严格用于娱乐目的,或者如果您不能将.Net 4.0+或3.5与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;
   }

注:

  • 确保您了解如何处理代码中的任何锁定/同步,因此在多个地方使用该变量时要非常小心。考虑使用锁包装对变量的访问
  • 考虑将值复制到锁内的局部变量,并在"需要值"的代码中使用局部变量。否则,其他线程可能会将其更改为新值/null
  • 对于一次性设置的变量,考虑处理这种初始化的CCD_ 18类,或者使用CCD_