TryRecv() = Object reference not set to an instance of an object
xAL95 opened this issue · 1 comments
When sending packets (repeadetly 100+) 3-5 times, then null reference exception occurs.
Important. This ONLY happens when using
new PoolSegManager.Kcp()
and loop without delay/sleep.
With sleep/delay 1 then there is no issue.
Example error code:
var kcp = new PoolSegManager.Kcp(12, this);
kcp.NoDelay(1, 10, 2, 1);
kcp.WndSize(64, 64);
kcp.SetMtu(512);
Task.Run(() =>
{
while (true)
{
kcp.Update(DateTime.UtcNow);
try
{
int len;
do
{
var (buffer, avalidSzie) = kcp.TryRecv();
len = avalidSzie;
if (buffer != null)
{
buffer.Dispose();
}
} while (len > 0);
}
catch(Exception e)
{
Console.WriteLine(e);
}
}
});
Bug已经复现。
为什么只有PoolSegManager才有Bug?
因为只有PoolSegManager的PoolSegManager.Seg是class,才会出现空引用。
怀疑的两个可能性:
1:TryRecv()的 rcv_queue.Count == 0 判断后,var seq = rcv_queue[0]; 执行前,存在其他线程删除了rcv_queue中的元素。
Q:通过代码分析,删除元素只有 UncheckRecv(Span buffer) 中 rcv_queue.RemoveRange(0, count); 一处。并且只在Recv环节调用,并不存在多线程问题。
2: https://source.dot.net/#System.Private.CoreLib/List.cs,203 rcv_queue.Add(seg);环节,是先增加size,后对下标赋值。
是不是有可能,rcv_queue.Count == 0 判断,var seq = rcv_queue[0]; 正好在List.Add中间执行?
直觉上这种可能性很小,但也不是没有。
一个佐证,但不能确定。在rcv_queue.Count == 0 判断,var seq = rcv_queue[0];两句代码之间插入了日志。Console.WriteLine($"rcv_queue TryRecv正在检测 rcv_queue[0]{rcv_queue[0]} ManagedThreadId{System.Threading.Thread.CurrentThread.ManagedThreadId}");
Bug消失了。
为什么sleep/delay 1 不出现Bug?
测试用例中如果delay,正好可以将Add和Recv函数错开调用。