我有一个由事件处理程序启动的函数。在此函数中,创建一个新任务并运行以设置一个全局变量,稍后我将在另一个事件处理程序中设置该变量。
这两者之间还有一些其他功能,它们不会改变这些中使用的任何变量。但这就是它的样子。
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
或其他任何内容。我可以尝试其他任何事情吗?
**注意我不能通过改变事件的排序/处理/工作方式来做很多事情。这是一个非常漂亮的石头设计,我只需要解决它并保持它或多或少的方式。
**更新
我也尝试将ParallelExtensionsExtras
与OrderedTaskScheduler
类一起使用,我仍然最终得到了我需要的变量的空引用。
答案 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;
}
注意:
Lazy<T>
类,或者使用Cache
来存储值更合适。