首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >将Thread.Join(timeLapse)转换为等效的非线程模式

将Thread.Join(timeLapse)转换为等效的非线程模式
EN

Stack Overflow用户
提问于 2017-07-07 08:50:01
回答 3查看 66关注 0票数 0

我有以下代码:

代码语言:javascript
复制
Thread validationThread = new Thread(DoAsyncValidationMethod);

validationThread.Start(threadParams);

bool isAborted = false;

int timeLeft = 5000;

// wait for thread terminates itself
if (!validationThread.Join(timeLeft))
{
    // timeout, abort thread
    validationThread.Abort();
    isAborted = true;
}

换句话说,我正在做一些应该在指定的时间间隔(5000毫秒)内完成的工作。如果完成或未完成,采用的线程方法将保证代码在启动后不晚于5秒返回。

有没有一种方法可以通过异步/等待模式来实现这一点?或者,既然线程只是用来玩把戏的,有没有其他方法可以采取呢?

越优雅、越简单越好。谢谢你的帮助。

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2017-07-07 09:43:06

这是我在一个项目中使用的一段代码。

此外,还可以查看[MSDN上的Task.WhenAny(参数Task[]任务)方法](https://msdn.microsoft.com/en-us/library/hh194796(v=vs.110%29.aspx)。它返回已完成的任务。

代码语言:javascript
复制
var timeout = 5000;
var task = Task.Run(() => {
    Thread.Sleep(new Random().Next(3000, 7000));//Running time simulation!
    return "Say my name!";//Breaking Bad!
});
if (await Task.WhenAny(task, Task.Delay(timeout)) == task) {
    // Task completed within timeout.
    // What if the task is faulted or canceled.
    // I did not supply a cancellation token but it can easily be added
    // We re-await the task so that any exceptions/cancellation is rethrown.
    await task;
}
else {
    // timeout/cancellation logic
}
票数 2
EN

Stack Overflow用户

发布于 2017-07-07 16:14:05

使用CancellationTokenSource。来源是CancellationTokens的一家工厂。您可以将此令牌传递给您希望能够以一种整洁的方式取消其处理的每个人。当您想要取消具有来自同一CancellationTokenSourceCancellationToken的所有进程时,只需告诉CancellationTokenSource向它产生的所有CancellationTokens发送取消,从而取消具有来自此来源的令牌的所有进程。

更好的是,CancellationTokenSource有一个CancelAfter(some timeout)

让进程启动器为您提供cancellationToken是一种好的做法,这样您的进程启动器就可以在一次调用中决定要取消哪些进程。

代码语言:javascript
复制
public async Task<MyResult> MyProcessAsync(CancellationToken cancellationToken, ...)
{
    // do something lengthy processing, without await, regularly check if Cancellation requested
    while (stillProcessing)
    {
        cancellationToken.ThrowIfCancellationRequested();
        ... // process
    }

    // do some processing with async-await:
    await myDbContext.SaveChangesAsync(cancellationToken);
}

用法:

代码语言:javascript
复制
private async Task LengthyProcessing(...)
{
    CancellationTokenSource tokenSource = new CancellationTokenSource();
    tokenSource.CancelAfter(TimeSpan.FromSeconds(5));

    CancellationToken myCancellationToken = tokenSource.Token
    try
    {
       // Start one task, don't await yet:
       var myTask = await MyProcessAsync(myCancellationToken, ...)
       // during processing there will be regular check if cancellation requested
       // meanwhile, whenever myTask has to await, I can do some processing
       // I'll have to check for cancellation regularly also:

       while(...)
       {
           myCancellationToken.ThrowIfCancellationRequested();
           DoSomeProcessing();
           ...
       }

       MyResult result = await myTask;
       // if here, not cancelled. can use Result:
       ProcessResult(result);
    }
    catch (OperationCanceledException exc)
    {
        ProcessOperationCanceled();
    }
}

请注意,仅使用了一个CancelltionTokenSource。每当这个源认为某些东西应该被取消时,所有拥有来自这个源的令牌的线程都会收到关于取消请求的通知。

考虑使用bool CancellationToken.IsCancellationRequested,而不是通过CancellationToken.ThrowIfCancellationRequested()使用异常处理。

MSDN how to cancel a task and its children

票数 2
EN

Stack Overflow用户

发布于 2017-07-07 10:26:34

你可以用微软的Reactive Framework (NuGet "System.Reactive")很好地做到这一点。然后你可以这样做:

代码语言:javascript
复制
IObservable<bool> query =
    Observable.Amb(
        Observable.Timer(TimeSpan.FromSeconds(5.0)).Select(_ => false),
        Observable.Start(() => DoAsyncValidationMethod()).Select(_ => true));

IDisposable subscription =
    query.Subscribe(flag =>
    {
        /* `true` succeeded, `false` timed out */
    });
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/44960906

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档