2014-03-07 141 views
0

我想在C#中使用異步/等待功能編寫硬件庫。對於許多操作,將會有兩種方法,一種是異步運行的,另一種是同步運行異步方法。例如,考慮一下:在C中同步返回值異步方法的問題#

public override bool ReferenceRun(bool positiveDirection) { 
    var runTask = ReferenceRunAsync(positiveDirection); 
    return runTask.Result; 
} 

public override async Task<bool> ReferenceRunAsync(bool positiveDirection) { 
    String cmd = createAxisCommand(positiveDirection ? refRunPlusCmd : refRunMinusCmd); 
    bool writeOK = writeToCOMPort(cmd); 
    if (!writeOK) return false; 
    return await Task.Factory.StartNew(() => { 
     WaitForHalt(); 
     return setParameter(postitionParam, 0); 
    }); 
} 

形式thisthat答案,我懷疑這是確定調用runTask.Result以等待異步方法來完成,然後檢索結果。但是,當我運行代碼時,對ReferenceRun的調用永遠不會返回。當我在調試器中暫停執行時,我可以看到它掛在return runTask.Result聲明處。

這是怎麼回事?

編輯: 根據this,所要求的行爲,就可以實現這樣的:

public override bool ReferenceRun(bool positiveDirection) { 
    var runTask = Task<bool>.Run(async() => { return await ReferenceRunAsync(positiveDirection); }); 
    return runTask.Result; 
} 

回答

3

ReferenceRunAsync,當您使用await,當前同步上下文(通常是UI線程的上下文)被捕獲,繼續(在await指令後面)在該同步上下文上運行。但是,由於您正在同步等待ReferenceRun中的結果,因此線程已佔線並且無法執行延續,因此您會遇到死鎖。一個簡單的辦法是調用ConfigureAwait(false)對期待已久的任務,以避免拍攝背景:

return await Task.Factory.StartNew(() => { 
    WaitForHalt(); 
    return setParameter(postitionParam, 0); 
}).ConfigureAwait(false); 

反正一般你不應該暴露一個同步封裝一個異步方法,或者反過來。見斯蒂芬Toub的解釋:

與您的代碼的另一個問題是,ReferenceRunAsync不是真正同步的,這是因爲:

  • writeToCOMPort是阻塞IO操作(只是從名稱中猜測),所以ReferenceRunAsync方法將阻塞,直到該調用爲com plete
  • 方法剩下的只是卸載到一個不同的線程中,所以除了以避免阻塞調用者

在這種情況下,它很可能是最好只露出一個純粹的同步沒有實際的好處方法,並讓調用者將其卸載到另一個線程(如有必要)。

0
public override bool ReferenceRun(bool positiveDirection) { 
var runTask = ReferenceRunAsync(positiveDirection); 
runTask.Wait(); 
return runTask.Result;} 

試試這個。你需要開始任務,你可以使用結果。

+0

我確實嘗試過;它沒有工作。托馬斯·列維斯克的回答澄清了原因。 – Matz

+0

的確,但我認爲應該添加runTask.Wait來驗證結果是否設置爲在ReferenceRun中返回。抱歉答案應該是額外的。 –

+0

其實是的,但afaik'Task.Result'已經在等待任務完成了。 – Matz