对方法的调用进行排队

本文关键字:排队 调用 方法 | 更新日期: 2023-09-27 18:36:45

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

我的应用程序中有几个区域调用 SendAndGet 方法。我有一个计时器,每 100 毫秒调用一次,发生的事件也将调用此方法。我正在寻找一种将这些调用排队的方法,以便我可以允许该方法在允许下一次调用之前完成?不知道该怎么做。在发布之前做了很多谷歌搜索和必应搜索。我认为 TPL 对我不起作用?

对方法的调用进行排队

事实上,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;
}