【发布时间】:2014-04-21 15:54:07
【问题描述】:
我的代码在调用SerialPort 类的ReadTo() 方法时不确定地抛出ArgumentOutOfRangeException: Non-negative number required.:
public static void RetrieveCOMReadings(List<SuperSerialPort> ports)
{
Parallel.ForEach(ports,
port => port.Write(port.ReadCommand));
Parallel.ForEach(ports,
port =>
{
try
{
// this is the offending line.
string readto = port.ReadTo(port.TerminationCharacter);
port.ResponseData = port.DataToMatch.Match(readto).Value;
}
catch (Exception ex)
{
Debug.WriteLine(ex.Message);
port.ResponseData = null;
}
});
}
SuperSerialPort 是SerialPort 类的扩展,主要用于保存特定于端口上每个设备的通信所需的信息。
端口总是定义了TerminationCharacter;
大多数时候是换行符:
我不明白为什么会这样。
如果 ReadTo 未能找到输入缓冲区中指定的字符,它不应该只是超时并且什么都不返回吗?
StackTrace 指向 mscorlib 中的一个违规函数,在 SerialPort 类的定义中:
System.ArgumentOutOfRangeException occurred
HResult=-2146233086
Message=Non-negative number required.
Parameter name: byteCount
Source=mscorlib
ParamName=byteCount
StackTrace:
at System.Text.ASCIIEncoding.GetMaxCharCount(Int32 byteCount)
InnerException:
我跟着它,这是我发现的:
private int ReadBufferIntoChars(char[] buffer, int offset, int count, bool countMultiByteCharsAsOne)
{
Debug.Assert(count != 0, "Count should never be zero. We will probably see bugs further down if count is 0.");
int bytesToRead = Math.Min(count, CachedBytesToRead);
// There are lots of checks to determine if this really is a single byte encoding with no
// funky fallbacks that would make it not single byte
DecoderReplacementFallback fallback = encoding.DecoderFallback as DecoderReplacementFallback;
----> THIS LINE
if (encoding.IsSingleByte && encoding.GetMaxCharCount(bytesToRead) == bytesToRead &&
fallback != null && fallback.MaxCharCount == 1)
{
// kill ASCII/ANSI encoding easily.
// read at least one and at most *count* characters
decoder.GetChars(inBuffer, readPos, bytesToRead, buffer, offset);
bytesToRead 被分配一个负数,因为 CachedBytesToRead 是负数。内联 cmets 指定 CachedBytesToRead 永远不能为负数,但显然是这样:
private int readPos = 0; // position of next byte to read in the read buffer. readPos <= readLen
private int readLen = 0; // position of first unreadable byte => CachedBytesToRead is the number of readable bytes left.
private int CachedBytesToRead {
get {
return readLen - readPos;
}
有人对为什么会发生这种情况有任何合理的解释吗?
我不相信我在读/写/访问串行端口方面做任何非法的事情。
这被不断抛出,没有好的方法来重现它。
输入缓冲区上有可用的字节,在这里您可以看到一些关键属性在中断时的状态(readLen、readPos、BytesToRead、CachedBytesToRead):
我是不是做错了什么?
编辑:显示同一端口未从循环异步访问的图片:
【问题讨论】:
-
我在使用串行端口方面的经验为零,所以请原谅我:您知道错误发生时您在流中的哪个位置吗?对我来说,您似乎在您的位置为 -1 且长度为零的流的开始或“结束”处遇到错误。也就是说,readPos 为零,长度为-1?这会导致 CachedBytesToRead 为负数。那可能对您没有帮助?
-
@rune711 你可以在最后一个截图中看到
readPos是 5,readLen是 2。这仍然是CachedBytesToRead是 -3。你会认为如果CachedBytesToRead小于bytesToRead它会尝试从端口读取另一个块。 -
readLen 和 readPos 是 mscorlib.dll 中 SerialPort 实现的私有成员。我无法控制他们。我包括了关于它们的简介,因为它说明了为什么抛出异常,而不是 为什么 它正在发生,我不知道。我所做的只是在向端口写入一些数据后在端口上调用 ReadTo(NewLine) 以捕获它的响应。我事先知道数据是如何终止的。
-
TerminationCharacters 之间需要多少数据?您可能会溢出某个大小的内部整数。
-
ports是否有可能多次包含同一个端口,因此您的Parallel.ForEach从同一个端口并行读取?
标签: c# .net winforms serial-port parallel.foreach