将任务标记为已完成

时间:2014-05-30 04:07:27

标签: c# asynchronous task-parallel-library task

我正在通过TCP / IP实现客户端协议MyProtocol。协议的Connect()方法应该具有类似于TcpClient.ConnectAsync()的签名 - 也就是说,它应该返回一个任务:

Task MyProtocol.Connect (…);

此方法(MyProtocol.Connect())应进行异步TCP / IP连接(通过TcpClient.ConnectAsync()),返回未完成的任务T,然后定期向服务器发送特定消息M - 再次异步(通过NetworkStream.WriteAsync())。当从服务器收到某个响应R时 - 再次异步(通过NetworkStream.ReadAsync()),MyProtocol.Connect()应该完成任务T. 我正在做以下事情:

    // Client of the protocol:
var task = myProtocol.Connect(); // asynchronous call, we don’t want to wait until connected
task.ContinueWith(t =>
{
    // Connected – doing an OnConnected stuff
    …
});

// MyProtocol.Connect() implementation:
public class MyProtocol
{
    private Task connectTask;
    public Task Connect(…)
    {
        var tcpIpConnectTask = mTcpIpProtocol.Connect(…);
        tcpIpConnectTask.ContinueWith(t =>
        {
            connectTask = new Task();
        }
        return connectTask;
    }
}

显然必须通过计时器定期向服务器发送消息M.一旦从服务器异步接收到响应R,connectTask必须标记为已完成,我看不到这样做的方法。 好吧,严格来说,我已设法将connectTask标记为已完成;我将它包装在TaskCompletionSource<bool>中并使用TaskCompletionSource.SetResult(true)。 但是我想知道这是否是唯一的,更不用说完成我需要的最好方法了?我特别不喜欢TaskCompletionSource<>必须具有非void任务结果类型(我使用bool)的事实,即没有非泛型版本。

在TPL到达之前,我们有自己的类似框架和方法Task.NotifyCompleted(),因此我们可以在一个地方创建一个任务,并在另一个地方将其标记为已完成 - 所有这些都是异步工作的。但是我在TPL中读到的关于任务的所有内容似乎都暗示,只有当委托的代理运行到最后一行时,任务才会完成... 或者我错过了一些简单的东西?

2 个答案:

答案 0 :(得分:3)

由于您已经在使用.Net 4.5,因此您应该使用C#5.0 async - await,这意味着完全适合这种情况。代码可能看起来像(有些伪编码):

public Task ConnectAsync()
{
    await ClientConnectAsync();

    while (true)
    {
        await SendMessageAsync();

        var response = await ReceiveMessageAsync();

        if (response == R)
            return;

        await Task.Delay(period);
    }
}

要真正回答您的问题:

  

但是我想知道这是否是唯一的,更不用说完成我需要的最佳方式了?

如果您不想使用async - await,那么是,TaskCompletionSource是执行此操作的唯一通用方法。

  

我特别不喜欢TaskCompletionSource<>必须具有非void任务结果类型(我使用bool)的事实,即没有非泛型版本。

这有点令人讨厌,但这并不重要,因为Task<T>继承自Task

  

但我在TPL中读到的任何内容似乎都暗示,只有当委托的代表运行到最后一行时,任务才会完成[...]

对于有代理要运行的Task,情况属实(可以使用Task.Run()Task.Factory.StartNew()new Task()创建代理。但它不适用于没有委托的Task,可以使用async - awaitTaskCompletionSource创建。

答案 1 :(得分:1)

我没有对此进行过测试,但有可能通过多个任务延续来实现您想要的效果,并且一旦收到所需的响应,请将connectedTask设置为从上一个ReadAsync收到的任务

public class MyProtocol
{
    private Task connectTask;
    public Task Connect()
    {
        var tcpIpConnectTask = mTcpIpProtocol.Connect();
        tcpIpConnectTask.ContinueWith(t =>
        {
            bool finished = false;
            Task readAsyncTask = null;

            while(!finsihed)
            {              
                NetworkStream.WriteASync().
                ContinueWith(t1 =>
                {
                     if(t1.Exception == null)
                     {                  
                        readAsyncTask = NetworkStream.ReadASync().
                        ContinueWiht(t2 => 
                        {
                            if(t2.Exception == null)
                            {
                                if(t2.Result == /*Desired Response*/)
                                { 
                                    finished = true;
                                    connectedTask = t2;
                                }
                            }
                            else
                            {   
                                // Handle ReadAsync error
                            }
                        }, null, TaskScheduler.Default);
                    }
                    else
                    {
                       // handle WriteAsync error
                    }
                }, null, TaskScheduler.Default);    

                // Wait for the read operation to complete. This can cause a deadlock
                // when called from a UI thread as Wait() is a blocking call. Ensure we are waiting
                // on a background thread by specifying TaskScheduler.Default
                readAsyncTask.Wait();
            }
        }, null, TaskScheduler.Default);

        return connectTask;
}

或者,如果您希望任务具有特定结果,则可以返回Task.FromResult(..),这也是一项已完成的任务。