有一些代码通过调用 GetBuffer() 将数据直接写入 MemoryStream 对象的数据缓冲区。它还适当地使用和更新 Position 和 SetLength() 属性。
此代码在 99.9999% 的时间内都能正常工作。字面上地。只有每这么多 100,000 次迭代它才会呕吐。具体问题是 MemoryStream 的 Position 属性突然返回零而不是适当的值。
但是,添加了检查 0 并引发异常的代码,该异常在单独的方法中包含 MemoryStream 属性(如 Position 和 Length)的日志。那些返回正确的值。在同一方法中进一步添加日志记录表明,当这种罕见情况发生时,位置在此特定方法内仅为零。
好的。显然,这一定是线程问题。并且很可能是编译器优化问题。
然而,这个软件的本质是它是由带有调度程序的“任务”组织的,因此几个实际的 O/S 线程中的任何一个都可以在任何给定时间运行这个代码——但一次不能超过一个。
所以我的猜测是,通常情况下,同一个线程一直被用于此方法,然后在极少数情况下使用不同的线程。(只需编写代码来通过捕获和比较线程 ID 来测试这个理论。)
然后由于编译器优化,不同的线程永远不会得到正确的值。它得到一个“陈旧”的价值。
通常在这种情况下,我会将“volatile”关键字应用于相关变量,以查看是否可以修复它。但在这种情况下,变量位于 MemoryStream 对象内。
有没有人有其他想法?或者这是否意味着我们必须实现自己的 MemoryStream 对象?
真诚的,韦恩
编辑:刚刚运行了一个测试,该测试计算对该方法的调用总数,并计算 ManagedThreadId 与上次调用不同的次数。它几乎恰好有 50% 的时间切换线程——在它们之间交替。所以我上面的理论几乎肯定是错误的,或者错误会更频繁地发生。
编辑:这个错误发生得非常少,以至于在没有这个错误的情况下需要将近一周的时间才能感觉到它真的消失了。相反,最好进行实验以准确确认问题的性质。
编辑:当前锁定是通过使用 MemoryStream 的 5 个方法中的每个方法中的 lock() 语句处理的。