任务和全局变量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程序,它会很好地工作,但即使我这样做了,我也需要它工作。
我能做些什么来克服这些比赛条件吗?
我试过使用.ContinueWith
和OnlyOnRanToCompletion
或其他什么选项。我还可以尝试其他东西吗?
**请注意,我无法更改事件的排序/处理/处理方式。这是一个漂亮的石头设计,我只需要围绕它工作,并或多或少地保持原样。
**更新
我还尝试过将ParallelExtensionsExtras
与OrderedTaskScheduler
类一起使用,但最终还是得到了对所需变量的null引用。
当您有一个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_