C# 创建循环到true或timeout的等待任务
我试图使用下面的函数不返回真/假,除非布尔函数arg返回真或超时过期。在当前状态下,如果布尔函数arg返回false,它将立即返回false,而不是循环并重试X毫秒C# 创建循环到true或timeout的等待任务,c#,async-await,C#,Async Await,我试图使用下面的函数不返回真/假,除非布尔函数arg返回真或超时过期。在当前状态下,如果布尔函数arg返回false,它将立即返回false,而不是循环并重试X毫秒 public delegate bool BooleanFunction (); public static async Task<bool> Wait(uint Milliseconds, BooleanFunction Function) { var StartTime = Env
public delegate bool BooleanFunction ();
public static async Task<bool> Wait(uint Milliseconds, BooleanFunction Function)
{
var StartTime = Environment.TickCount;
do
{
if (Function())
{
return true;
}
Thread.Yield();
}
while (Environment.TickCount < StartTime + Milliseconds);
return false;
}
公共委托布尔布尔函数();
公共静态异步任务等待(uint毫秒,布尔函数)
{
var StartTime=Environment.TickCount;
做
{
if(函数())
{
返回true;
}
螺纹屈服强度();
}
while(Environment.TickCount
您需要使用等待任务。收益
而不是线程。收益
if (Function())
{
return true;
}
await Task.Yield();
如果您还希望处理将异步委托传递到Wait
,请保留现有版本并添加以下重载:
public static async Task<bool> Wait(uint Milliseconds, Func<Task<bool>> Function)
{
var StartTime = Environment.TickCount;
do
{
if (await Function())
{
return true;
}
Thread.Yield();
}
while (Environment.TickCount < StartTime + Milliseconds);
return false;
}
Microsoft提出了另一种实现方法,即使用cancellationTokenSource和cancellationToken StackOverflow还有一些与此相关的主题: 转化为您的问题,调用方不会传递委托函数,而是传递System.Threading.CancellationToken对象。Wait函数不调用委托,而是定期检查CancellationToken对象是否请求取消 这个方法和你的非常相似,只是它是一个更标准的模式。真正的好处是,您可以在一次调用中取消所有使用同一来源令牌的任务。此外,它还有一个内置的超时功能 另一个优点是,取消的原因在函数外部决定,可以是超时,也可以是因为BooleanFunction返回true,甚至可能是因为程序停止等。即使在将来的版本中引入了新的停止等待的原因,您的等待函数也不必更改。它所做的只是做好工作,并定期检查是否需要取消 示例代码: 你的等待函数没有做很多事情,只是等待。我猜你简化了这个,因为如果这就是它真正需要做的,我猜你使用了System.Timer。让我们假设你必须做点什么 我有一个有两个按钮的表单:buttonStartWait和buttonCancelWait。按下按钮时,buttonStartWait将启动等待,而buttonCancelWait将取消等待 如果我们使用了您的方法,buttonCancelWait将使委托返回true 代码如下所示(我还将Ticks的用法改为TimeSpan,以便于阅读)
private CancellationTokenSource-tokenSource=null;
私有异步无效OnButtonStartWait_已单击(对象发送方,…)
{
this.buttonStartWait.Enabled=false;
TimeSpan waitTime=GetWaitTime();
this.tokenSource=新的tokenSource(waitTime);
//这确保在等待时间后取消请求
Wait this.Wait(this.TokenSource.Token);
this.buttonstartWait.Enabled=true;
}
专用异步任务等待(CancellationToken令牌)
{
而(!token.IsCancellationRequested)
{//做你的职责应该做的事情。
DoSomethingShort();
//如果此函数需要一些时间,请将令牌传递给它
//并让it部门定期检查是否有取消申请
DoSomethingLonger(代币);
或考虑启动定期检查的任务。
//如果要求取消
等待任务。运行(()=>DoSomethingLonger(令牌),令牌);
}
return token.IsCancellationRequested;
}
//一个Wait函数,除了Wait之外什么都不做
//直到要求取消为止。
专用异步任务等待(CancellationToken令牌)
{
而(!token.IsCancellationRequested)
{//请稍等
等待任务。等待(TimeSpan.FromSeconds(0.1),令牌;
}
return token.IsCancellationRequested;
}
私有异步无效OnButtonCancelWait_已单击(对象发送方,…)
{
if(this.TokenSource!=null)
{
this.TokenSource.Cancel();
}
}
这在Linqpad中工作,您如何测试它?谢谢ned,我已经做了一些调整,但是我无法正确调用它。错误:code:edit:updated code这是因为您的Wait
函数只处理同步委托和Test()
是async
,请参阅我的更新答案以处理async
问题。
var result = await Wait(10000, async () => await Test());
private CancellationTokenSource tokenSource = null;
private async void OnButtonStartWait_clicked(object sender, ...)
{
this.buttonStartWait.Enabled = false;
TimeSpan waitTime = GetWaitTime();
this.tokenSource = new tokenSource(waitTime);
// this makes sure that after waitTime cancellation is requested
await this.Wait(this.TokenSource.Token);
this.buttonstartWait.Enabled = true;
}
private async Task<bool> Wait(CancellationToken token)
{
while (!token.IsCancellationRequested)
{ // do the thing your function is supposed to do.
DoSomethingShort();
// if this function takes some time, pass the token to it
// and let it regularly check if cancellation is requested
DoSomethingLonger(token);
// or consider starting a Task which regularly checks
// if cancellation is requested
await Task.Run( () => DoSomethingLonger(token), token);
}
return token.IsCancellationRequested;
}
// a Wait function that really doesn't do anything but wait
// until cancellation is requested.
private async Task<bool> Wait(CancellationToken token)
{
while (!token.IsCancellationRequested)
{ // wait a short while
await Task.Wait(TimeSpan.FromSeconds(0.1), token;
}
return token.IsCancellationRequested;
}
private async void OnButtonCancelWait_clicked(object sender, ...)
{
if (this.TokenSource != null)
{
this.TokenSource.Cancel();
}
}