在不阻塞的情况下等待变量

本文关键字:情况下 等待 变量 | 更新日期: 2023-09-27 18:23:35

我有一个c#程序,其中function1需要在不阻塞程序的情况下等待变量变为true。从外部脚本异步调用的function2将变量设置为true。有没有一种方法可以在不阻止调用function2的情况下在function1中中途等待?在function2将变量设置为true之后,我需要继续执行function 1的其余部分。

 bool doneProcessing;
 public void function1(string someParameter)
 {
   doneProcessing = false;
   InvokeScript(somevalue);
   //Wait till variable doneProcessing becomes true;
   //Continue from here after doneProcessing is true
  }
public void function2(string someParameter)
 {
   doneProcessing = true;
   return;
  }

在不阻塞的情况下等待变量

TaskCompletionSource是您的朋友

 bool doneProcessing;
 TaskCompletionSource < bool > tcs = new TaskCompletionSource < bool > ();

 public void function1(string someParameter)
 {
     doneProcessing = false;
     Task < bool > b = InvokeScript("IDontCare");
 Console.WriteLine ("What's up?...");
     b.ContinueWith(_ => Console.WriteLine("finished!")); //magic is here
 Console.WriteLine ("Im not blocking...");
 }

 public Task < bool > function2(string someParameter)
 {

 new Thread(()=> {Thread.Sleep(2000); tcs.SetResult(true); /*this simulate putting true in doneProcessing variable*/}).Start();
     return tcs.Task;
 }
 public Task < bool > InvokeScript(string someParameter)
 {
     return function2(someParameter);
 }

 void Main()
 {
     function1("1");
     Console.ReadLine();    
 } 
// output :What's up?...
Im not blocking...
finished

最简单的方法可能是

  • 将委托传递到function2中,以便在其结束时调用该函数
  • 或者创建自定义事件(例如)Function2Complete并且从function1订阅它

如果这不是你想要的,请澄清。

正如有人在评论中所说,你不能不阻止就等待
但是,您可以等待而不必等待

这完全取决于你所说的"等待"这个词到底是什么意思。

通常,您只希望在满足一组条件时执行一段代码。但这并不意味着你必须阻止任何事情。

考虑一下:

bool condition1 = false;
bool condition2 = false;
bool condition3 = false;
aFunction1() { condition1 = true; }
aFunction2() { condition2 = true; }
aFunction3() { condition3 = true; }
whenJobHasBeenCompleted() { console.writeline("all three were done!"); }
// and I'd like to have it automagically called..:
if(cond1 && cond2 && cond3) whenJobHasBeenCompleted();

所以,很明显,我希望在调用完之前的所有函数后执行最后一个函数,但我并不在乎是谁调用了它们,也不在乎顺序是什么。

有很多工具*),但请考虑最简单、最明显的:普通.Net事件":

bool condition1 = false;
bool condition2 = false;
bool condition3 = false;
event eventhandler VariableHasChanged;
aFunction1() { condition1 = true; VariableHasChanged(); }
aFunction2() { condition2 = true; VariableHasChanged(); }
aFunction3() { condition3 = true; VariableHasChanged(); }
VariableHasChanged += whenJobHasBeenCompleted;
whenJobHasBeenCompleted()
{ 
    if( !( condition1 && condition2 && condition3 ) )
       return;
    // VariableHasChanged -= whenJobHasBeenCompleted
    console.writeline("all three were done!");
}

这种类似状态机的方法可能是最容易理解的。在使用其他更复杂的工具之前,请使用它进行培训,直到您对这种方法的优缺点有了很好的了解。

现在,正如我所说,有许多其他方式。

  • 对于事件,您经常会遇到多线程和正确清理的问题。因此,您可以使用任何Eventing/Notification框架,例如来自Prism/CAG的WeakEvents或CompositeEvents,这些问题可能会消失。

  • 您可以创建一组(智能)属性并绑定到它们,而不是使用事件。如果使用任何XAMLish UI,您可以很容易地编写一个触发器/多绑定,它将观察三个源,并仅在三个源都设置好时做出反应。

  • 你可以使用一个工作线程和条件变量(或者你可以像Royi建议的那样使用TaskCompletionSource,它对你隐藏了大部分)。

  • 您可以获取Rx Framework,并使用热可观察而不是变量,并将它们连接/过滤以创建一个过滤的事件流,该流仅在所有三个变量都设置为特定值时发出ping信号。

  • 或者,如果你不喜欢,你可以将RX与普通变量/事件一起使用,并将你的事件重新连接到IObservable中,而不需要任何"主题"answers"OnNext"。。

  • 或者。。。