队列调用方法

时间:2015-01-08 21:33:48

标签: c# .net winapi task-parallel-library

我有一个C#方法(SendAndGet),它向串口发送一条消息,等待响应或超时。我正在使用System.IO.SerialPort与串行端口进行通信。

我的应用程序中有几个区域调用SendAndGet方法。我有一个定时器,每100毫秒调用一次,发生的事件也会调用此方法。我正在寻找一种方法来排队这些调用,以便我可以允许该方法在允许下一次调用之前完成?不知道该怎么做。在发布之前进行了大量的Google搜索和bing搜索。我不认为TPL会对我有用吗?

1 个答案:

答案 0 :(得分:1)

事实上,TPL比以前的选项更容易使用。

我们要做的是创建一个包装SerialPort的类,公开异步方法来发送请求并获得响应,通过单个端口对请求进行排队。

此类还有一个私有Task,代表发出的最后一个请求;当一个新请求进入时,它会为该任务添加一个继续,以开始执行其实际工作,然后将自己指定为新的"最后一个任务"。

对于SendAndGet方法的实际实施,我们await最后一项任务,以便我们不会在最后一项任务完成之前启动,然后我们可以发送数据通过端口,等待接收数据(异步)并处理结果。请注意,在您的情况下,您可能希望将方法的返回类型从Task更改为Task<T>,其中T是您从序列中解析出的实际数据端口。

public class AsyncSerialPort
{
    private SerialPort port;
    private Task lastRequest = Task.FromResult(true);
    public AsyncSerialPort()
    {
        //initialize port here
    }

    public Task SendAndGet()
    {
        lock (lastRequest)
        {
            var result = SendAndGetImpl();
            lastRequest = result;
            return result;
        }
    }
    private async Task SendAndGetImpl()
    {
        await lastRequest;
        //send data to port
        var type = await port.WhenDataRecieved();
        //process the received data

    }
}

我们需要的另一件事是WhenDataRecieved的实施;某种方式可以获得代表收到数据的Task,以便我们可以await

public static Task<SerialData> WhenDataRecieved(this SerialPort port)
{
    var tcs = new TaskCompletionSource<SerialData>();
    SerialDataReceivedEventHandler handler = null;
    handler = (s, args) =>
    {
        tcs.TrySetResult(args.EventType);
        port.DataReceived -= handler;
    };
    port.DataReceived += handler;
    return tcs.Task;
}