我必须在哪里抛出异常以防止在任务中无休止地等待
Where must i throw an exception to prevent endless waiting in Task
我有一个硬件设备通过串行端口连接到我的 PC,当我向它发送信号时,它会发回信号 "Hi, here I am!",然后成功检测到它所连接的端口。我用 C# 写了一个等待硬件设备响应的任务,但是如果它没有连接,那么这个任务就会永远等待。我在哪里可以抛出异常来防止这种无休止的等待?
我的代码:
public static Task<string> GetDevicePortName()
{
// Get all available serial ports on system.
var ports = SerialPort.GetPortNames();
var serialPort = new SerialPort();
serialPort.BaudRate = Constants.DeviceConstants.BaudRate;
serialPort.Parity = Constants.DeviceConstants.SerialPortParity;
serialPort.StopBits = Constants.DeviceConstants.SerialPortStopBits;
serialPort.WriteTimeout = Constants.DeviceConstants.WriteTimeoutInMilliseconds;
var taskCompletionSource = new TaskCompletionSource<string>();
serialPort.DataReceived += (s, e) =>
{
var dataIn = (byte)serialPort.ReadByte();
var receivedCharacter = Convert.ToChar(dataIn);
if (receivedCharacter == Constants.DeviceConstants.SignalYes)
{
serialPort.Dispose();
taskCompletionSource.SetResult(serialPort.PortName);
}
};
foreach (var port in ports)
{
serialPort.PortName = port;
try
{
serialPort.Open();
serialPort.Write(Constants.DeviceConstants.SignalDeviceDetect);
}
catch (IOException e) { }
}
return taskCompletionSource.Task;
}
您可以创建一个 "Custom timeout" 组合 Task.WhenAny
与 Task.Delay
:
public async Task GetDevicePortNameAsync()
{
var cts = new CancellationTokenSource();
var timeOutTask = Task.Delay(5000, cts.Token);
var deviceNameTask = GetDevicePortName(cts.Token);
var finishedTask = await Task.WhenAny(timeOut, deviceNameTask);
if (finishedTask == timeOutTask)
{
// You've timed-out
}
// If you get here, the deviceName is available.
}
请注意,这 不会 取消对 SerialPort
的基础注册。
编辑:
@KDecker 添加了一个传递 CancellationToken
的想法,如果我们在返回 TaskCompletionSource.Task
之前已经超时,可以对其进行监控。它看起来像这样:
public static Task<string> GetDevicePortName(CancellationToken cancellationToken)
{
// Get all available serial ports on system.
var ports = SerialPort.GetPortNames();
var serialPort = new SerialPort();
serialPort.BaudRate = Constants.DeviceConstants.BaudRate;
serialPort.Parity = Constants.DeviceConstants.SerialPortParity;
serialPort.StopBits = Constants.DeviceConstants.SerialPortStopBits;
serialPort.WriteTimeout = Constants.DeviceConstants.WriteTimeoutInMilliseconds;
var taskCompletionSource = new TaskCompletionSource<string>();
serialPort.DataReceived += (s, e) =>
{
var dataIn = (byte)serialPort.ReadByte();
var receivedCharacter = Convert.ToChar(dataIn);
if (receivedCharacter == Constants.DeviceConstants.SignalYes)
{
serialPort.Dispose();
taskCompletionSource.SetResult(serialPort.PortName);
}
};
foreach (var port in ports)
{
if (cancellationToken.IsCancellationRequested)
{
// Unregister from serialPort, and clean up whatever needs to be cleaned
taskCompletionSource.SetResult(null);
break;
}
serialPort.PortName = port;
try
{
serialPort.Open();
serialPort.Write(Constants.DeviceConstants.SignalDeviceDetect);
}
catch (IOException e) { }
finally
{
serialPort.Dispose();
}
}
return taskCompletionSource.Task;
}
我有一个硬件设备通过串行端口连接到我的 PC,当我向它发送信号时,它会发回信号 "Hi, here I am!",然后成功检测到它所连接的端口。我用 C# 写了一个等待硬件设备响应的任务,但是如果它没有连接,那么这个任务就会永远等待。我在哪里可以抛出异常来防止这种无休止的等待?
我的代码:
public static Task<string> GetDevicePortName()
{
// Get all available serial ports on system.
var ports = SerialPort.GetPortNames();
var serialPort = new SerialPort();
serialPort.BaudRate = Constants.DeviceConstants.BaudRate;
serialPort.Parity = Constants.DeviceConstants.SerialPortParity;
serialPort.StopBits = Constants.DeviceConstants.SerialPortStopBits;
serialPort.WriteTimeout = Constants.DeviceConstants.WriteTimeoutInMilliseconds;
var taskCompletionSource = new TaskCompletionSource<string>();
serialPort.DataReceived += (s, e) =>
{
var dataIn = (byte)serialPort.ReadByte();
var receivedCharacter = Convert.ToChar(dataIn);
if (receivedCharacter == Constants.DeviceConstants.SignalYes)
{
serialPort.Dispose();
taskCompletionSource.SetResult(serialPort.PortName);
}
};
foreach (var port in ports)
{
serialPort.PortName = port;
try
{
serialPort.Open();
serialPort.Write(Constants.DeviceConstants.SignalDeviceDetect);
}
catch (IOException e) { }
}
return taskCompletionSource.Task;
}
您可以创建一个 "Custom timeout" 组合 Task.WhenAny
与 Task.Delay
:
public async Task GetDevicePortNameAsync()
{
var cts = new CancellationTokenSource();
var timeOutTask = Task.Delay(5000, cts.Token);
var deviceNameTask = GetDevicePortName(cts.Token);
var finishedTask = await Task.WhenAny(timeOut, deviceNameTask);
if (finishedTask == timeOutTask)
{
// You've timed-out
}
// If you get here, the deviceName is available.
}
请注意,这 不会 取消对 SerialPort
的基础注册。
编辑:
@KDecker 添加了一个传递 CancellationToken
的想法,如果我们在返回 TaskCompletionSource.Task
之前已经超时,可以对其进行监控。它看起来像这样:
public static Task<string> GetDevicePortName(CancellationToken cancellationToken)
{
// Get all available serial ports on system.
var ports = SerialPort.GetPortNames();
var serialPort = new SerialPort();
serialPort.BaudRate = Constants.DeviceConstants.BaudRate;
serialPort.Parity = Constants.DeviceConstants.SerialPortParity;
serialPort.StopBits = Constants.DeviceConstants.SerialPortStopBits;
serialPort.WriteTimeout = Constants.DeviceConstants.WriteTimeoutInMilliseconds;
var taskCompletionSource = new TaskCompletionSource<string>();
serialPort.DataReceived += (s, e) =>
{
var dataIn = (byte)serialPort.ReadByte();
var receivedCharacter = Convert.ToChar(dataIn);
if (receivedCharacter == Constants.DeviceConstants.SignalYes)
{
serialPort.Dispose();
taskCompletionSource.SetResult(serialPort.PortName);
}
};
foreach (var port in ports)
{
if (cancellationToken.IsCancellationRequested)
{
// Unregister from serialPort, and clean up whatever needs to be cleaned
taskCompletionSource.SetResult(null);
break;
}
serialPort.PortName = port;
try
{
serialPort.Open();
serialPort.Write(Constants.DeviceConstants.SignalDeviceDetect);
}
catch (IOException e) { }
finally
{
serialPort.Dispose();
}
}
return taskCompletionSource.Task;
}