2011-11-07 45 views
1

我剛剛意識到,當我從任務內啓動任務並調用Task.Wait時,新任務不會被內聯,而調用Task.Result將始終內聯任務。任務內聯和Task.Wait

當我們用RAII模式(在ExecuteWithCancel中實現)包裝我們的任務時,內聯將重新使用分配的資源並且是可取的。

但是我們有時候想等一段時間,然後取消任務。 等待的代碼如下所示:

using (var cts = new CancellationTokenSource()) 
{ 
    // Task scheduler decides whether to execute synchronous or asynchronous 
    var task = new Task<TResult>(() => ExecuteWithCancel<TResult>(cts.Token, nameOfTaskPerformer, arguments), cts.Token) 
    if (timeout==TimeSpan.Zero || task.Wait(timeout)) // this creates an all or nothing timeout 
     return task.Result; 
    cts.Cancel(); 
    throw new TimeoutException(""); 
} 

當超時TimeSpan.Zero任務是內聯,否則它總是使用另一個線程。

有沒有簡單的方法來重新設計這段代碼來使用內聯和等待/超時?

+0

你目前的代碼永遠不會啓動任務。要麼調用'task.Start',要麼使用'Task.Factory.StartNew'。請參閱http://blogs.msdn.com/b/pfxteam/archive/2011/10/24/10229468.aspx –

回答

2

很確定這是不可能的。假設你正在運行的線程A下面的代碼:

var task = Task.Factory.StartNew(() => Thread.Sleep(Timeout.Infinite)); 
task.Wait(5000); 

如果任務是內聯,線程A將無限期阻塞 - 怎麼會醒來後超時? 望着參考源(Task.cs),我們可以清楚地看到的是:

internal bool InternalWait(int millisecondsTimeout, CancellationToken cancellationToken) 
{ 
    ... 
    // we will attempt inline execution only if an infinite wait was requested 
    // Inline execution doesn't make sense for finite timeouts and if a cancellation token was specified 
    // because we don't know how long the task delegate will take. 
    if (millisecondsTimeout == Timeout.Infinite && !cancellationToken.CanBeCanceled && 
     WrappedTryRunInline() && IsCompleted) 
    { 
     returnValue = true; 
    } 
    else 
    { 
     returnValue = CompletedEvent.Wait(millisecondsTimeout, cancellationToken); 
    } 

根據您的問題,爲了從有限的超時內聯受益,你必須實現內部的超時邏輯任務本身,或許是這樣的:

ExecuteWithCancel<TResult>(cts.Token, TimeSpan timeout, nameOfTaskPerformer, arguments) 

然後使用普通Wait()(或Result)。

+0

這是我的解決方案... – sanosdole

+0

偉大的思想思考類似;)下次你可以回答你自己的問題其他人將能夠從你找到的解決方案中受益 –

+0

嗯,我在這裏有一個答案,解釋了爲什麼任務不能內聯,我圍繞此建立了解決方案。但是在我接受之前,答案已經被刪除了。所以這個問題被遺忘了...... – sanosdole

相關問題