我正在使用非常特定的使用TCP和SSL流的Web API。与API的连接是持久的(不应在每次写入/读取后关闭),因为此连接用于接收来自服务器的事件通知。创建异步方法并从另一种方法设置任务结果
所以,我实现了一个循环的阅读方法:
private void Listen()
{
int length;
do
{
var buffer = new byte[TcpClient.ReceiveBufferSize];
length = SslStream.Read(buffer, 0, TcpClient.ReceiveBufferSize);
if (length > 0)
{
// Process received data
Listen();
}
} while (length > 0);
//reconnect
}
现在我需要调用一些API方法。我希望他们支持TPL(异步和等待)。问题是这些方法的异步部分实际上是在上面的阅读方法(Listen)中实现的。例如:
public async Task<bool> Authenticate(string clientId, string clientSecret)
{
await SendAuthMessageOverNetwork(clientId, clientSecret);
return await ReceiveAuthResponseFromServer();
// The problem is that there is no ReceiveAuthResponseFromServer method -
// the response is received in reading thread (Listen).
}
我对TPL还不是很熟悉。我使用任务实际上并没有做任何事情,但是从读线程等待一个信号(的AutoResetEvent)解决了这个问题:
private AutoResetEvent _loginEvent;
private bool _loginResult;
public async Task<bool> Authenticate(string clientId, string clientSecret)
{
await SendAuthMessageOverNetwork(clientId, clientSecret);
return await Task<bool>.Factory.StartNew(() => { _loginEvent.WaitOne(); return _loginResult; });
}
private void Listen()
{
...
if (msg.Type == MessageTypes.AuthenticationResponse)
{
_loginResult = true;
_loginEvent.Set();
}
...
}
但我不太喜欢这种解决方案。也许有更简单的方法来实现我想要的?这可以通过仅使用任务功能完成,无需AutoResetEvent和中间全局变量?
谢谢!正是我需要的。 –
@AkkseyShubin应该注意到这里有一个微妙的时刻。如果启动了'await Task'的线程是一个带默认同步上下文的非UI线程,调用'_responseQueue.Dequeue().SetResult(msg)'将会立即调用继续回调(在'await'后面的代码)线程所在的'Listen()'正在运行。因此,'Listen'将被阻塞,直到消费者端的代码流中有另一个'await'。这可能会导致死锁,具体取决于逻辑工作流程。更多信息:http://stackoverflow.com/q/19481964/1768303 – Noseratio
@Noseratio正确。永远不要阻止任务,除非你了解TPL是如何工作的以及如何从上到下完成任务。 –