我有一个C#方法(SendAndGet),它向串口发送一条消息,等待响应或超时。我正在使用System.IO.SerialPort与串行端口进行通信。
我的应用程序中有几个区域调用SendAndGet方法。我有一个定时器,每100毫秒调用一次,发生的事件也会调用此方法。我正在寻找一种方法来排队这些调用,以便我可以允许该方法在允许下一次调用之前完成?不知道该怎么做。在发布之前进行了大量的Google搜索和bing搜索。我不认为TPL会对我有用吗?
答案 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;
}