Way*_*yne 6 .net c# multithreading memorystream volatile
有一些代码通过调用GetBuffer()将数据直接写入MemoryStream对象的数据缓冲区.它还适当地使用和更新Position和SetLength()属性.
此代码在99.9999%的时间内正常工作.从字面上看.只有每隔这么多的100,000次迭代才能实现.具体问题是MemoryStream的Position属性突然返回零而不是适当的值.
但是,添加了检查0的代码并抛出异常,其中包括在单独的方法中记录MemoryStream属性(如位置和长度).那些返回正确的值.在同一方法中进一步添加日志记录表明,当出现这种罕见情况时,Position在此特定方法中仅为零.
好的.显然,这必须是一个线程问题.而且很可能是编译器优化问题.
但是,这个软件的本质是它由调度程序的"任务"组织,因此几个实际的O/S线程中的任何一个都可以在任何给定时间运行此代码 - 但一次不得超过一个.
所以我的猜测通常会发生同样的线程不断用于此方法,然后在极少数情况下使用不同的线程.(只需编写想法,通过捕获和比较线程ID来测试这个理论.)
然后由于编译器优化,不同的线程永远不会得到正确的值.它得到一个"陈旧"的价值.
通常在这种情况下,我会将"volatile"关键字应用于相关变量,以查看是否可以修复它.但在这种情况下,变量位于MemoryStream对象中.
有没有人有任何其他想法?或者这是否意味着我们必须实现自己的MemoryStream对象?
真诚的,韦恩
编辑:只运行一个测试,计算此方法的调用总数,并计算ManagedThreadId与上次调用的次数不同的次数.它几乎完全是50%的时间切换线程 - 在它们之间交替.所以我上面的理论几乎肯定是错的,或者错误会更频繁地发生.
编辑:这个错误很少发生,它需要将近一个星期的运行没有错误之前感到有任何信心,它真的消失了.相反,最好运行实验来确切地确定问题的本质.
编辑:当前锁定是通过使用MemoryStream的5种方法中的每一种中的lock()语句来处理的.
(真的需要示例代码来证实这一点.)
MemoryStream成员没有记录为线程安全(例如Position),因此您需要确保您一次只能MemoryStream从一个线程访问此实例(或逻辑上对象的任何引用).
但MemoryStream在没有记载具有线程关联,这样你就可以从不同的线程,只要这样的访问是不是并发访问实例.
线程很难(这个问答的公理).
我建议您进行一些并发访问,两个线程同时访问同一个实例,这偶尔会破坏实例状态的某些方面.
我会确保尽可能简单地保持锁定(试图更加聪明,并且限制锁定通常是很难找到错误的原因)并使事情有效.在多核系统上进行测试也可能有所帮助.如果分析显示存在显着的净(应用程序整体)增益的潜力,则仅尝试并优化锁定.