微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

奇怪的线程NullReferenceException当读取存在的值?

公共字段读取我知道存在的对象的值时,我有一个令人难以置信的奇怪的NullReferenceException。 基本stream程是这样的:

编辑:我意识到我忘了提及一些重要的东西,每次我尝试读取Tag值时都不会发生这种情况,但是只有一次,足够我每次只需运行代码就可以重现它,而不是在代码运行时立即

服务器收到一条消息(Worker线程)

发送消息get的连接被设置为消息对象(工作线程)上的Tag字段

该消息被放入一个“ReceivedMessages”队列(一个正常的Queue对象,该对象被锁访问序列化) (Worker线程)

消息被读取(主线程)

我尝试读取消息的Tag字段以获得连接,这有时会返回null并引发exception,但是当抛出exception并检查Message对象时,可以看到Connection对象(它是Tag字段)有清晰的一天(主线程)

如果你看这张照片,你会看到清楚的一天:

我怎样才能从$(ProjectDir)中删除tralling反斜杠?

如何刷新未决的FileSystemWatcher事件?

如何设置.NET框架的作业调度?

我怎样才能找出谁在Windows中使用.NET创build一个文件

吐司通知不能在Windows秋季创作者更新

你可以看到我用绿色框标记的位置,我试着用三种不同的方式阅读message.Tag属性,它们全都返回null,就像你在标有蓝色框的部分中看到的那样。

但是,如果您查看标记为红色的两个区域,则可以看到该对象实际存在的date。 而且,为了清除任何混淆,消息被放在收到的消息队列中的部分如下所示:

我正如你所看到的,我甚至试着做一个Thread.VolatileWrite来确保值被写入

message.Tag = buffer.Tag; Thread.VolatileWrite(ref message.Tag,buffer.Tag); if (message.Tag == null) { isNullLog.Add(message.Id); } // Queue into received messages lock (peer.ReceivedMessages) { peer.ReceivedMessages.Enqueue(message); }

上面的代码片段都发生在工作线程中,正如你所看到的,我将buffer.Tag拷贝到message.Tag ,我甚至设置了一些运行时检查,用于debugging,检查message.Tag为空值并添加如果是这样的话,则将id列表称为“isNullLog”。 当NullReferenceException在主线程中被抛出时,这个列表是空的。

你也看到我locking了peer.ReceivedMessages队列,并在设置了message.Tag字段之后将消息推送到队列中。

此外,更清楚的是用于从peer.ReceivedMessages队列中读取消息的peer.ReceivedMessages 。

public bool TryGetMessage(out TIncomingMessage message) { lock (ReceivedMessages) { if (ReceivedMessages.Count > 0) { message = ReceivedMessages.Dequeue(); return true; } } ReceivedMessageEvent.Reset(); message = null; return false; }

你可以看到,我甚至在我检查计数之前locking队列,如果不是空的,我设置out属性并返回true,否则返回false。

老实说,我完全难住,写了几个multithreading应用程序之前,从来没有遇到过这个。

稍微更新一下,我也试着将Tag字段Tag为volatile ,使得它看起来像这个public volatile object Tag; 但这似乎没有帮助。

如何将Windows服务从本地PC移动到虚拟专用服务器上

如何在特殊的PowerShell链命令4命令提示符?

检测HWND可见性更改

什么是Windows平台的GPS中间驱动程序的等效物?

我应该在哪里存储适用于非漫游用户的机器范围的应用程序设置?

我现在确实已经解决了这个问题,就像在处理线程时一样,在读取/写入值时需要格外小心。 我忘了清除接收循环中的本地message变量,并在下一次循环迭代中“重复使用”相同的消息,因为它有一个if(message == null) { /* create new message */ } check before每一次迭代,当我不清除这个线程时,读取线程结束了对尝试写入新消息时存储在这里的“旧”消息的践踏。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 [email protected] 举报,一经查实,本站将立刻删除。

相关推荐