2014-03-07 105 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