c# - 不同线程访问 MemoryStream

标签 c# .net multithreading volatile memorystream

有一些代码通过调用 GetBuffer() 将数据直接写入 MemoryStream 对象的数据缓冲区。它还适本地使用和更新 Position 和 SetLength() 属性。

这段代码在 99.9999% 的时间里都能正常工作。字面上地。只有每 100,000 次迭代它才会呕吐。具体问题是 MemoryStream 的 Position 属性突然返回零,而不是适当的值。

但是,添加了检查 0 并抛出异常的代码,该异常在单独的方法中包含 MemoryStream 属性(如 Position 和 Length)的日志。那些返回正确的值。在同一方法中进一步添加日志记录表明,当这种罕见情况发生时,该特定方法中的 Position 只有零。

好的。显然,这一定是线程问题。并且很可能是编译器优化问题。

但是,该软件的本质是它是通过调度程序按“任务”组织的,因此多个实际 O/S 线程中的任何一个都可以在任何给定时间运行此代码——但一次最多只能运行一个.

所以我猜测通常情况下,同一个线程一直被用于此方法,然后在极少数情况下会使用不同的线程。 (通过捕获和比较线程 id 来编写想法来测试这个理论。)

然后由于编译器优化,不同的线程永远不会获得正确的值。它得到一个“过时”值。

通常在这种情况下,我会向有问题的变量应用“volatile”关键字,看看是否可以修复它。但在这种情况下,变量位于 MemoryStream 对象内。

有没有人有任何其他想法?或者这是否意味着我们必须实现自己的 MemoryStream 对象?

真诚的, 韦恩

编辑:刚刚运行了一个测试,计算对该方法的调用总数,并计算 ManagedThreadId 与上次调用不同的次数。它几乎恰好有 50% 的时间切换线程——在它们之间交替。所以我上面的理论几乎肯定是错误的,或者错误会更频繁地发生。

编辑:这个错误很少发生,以至于在没有这个错误的情况下运行将近一个星期才能确信它真的消失了。相反,最好进行实验以准确确认问题的性质。

编辑:目前,锁定是通过使用 MemoryStream 的 5 种方法中的每一种中的 lock() 语句处理的。

最佳答案

(确实需要示例代码来确认这一点。)

MemoryStream成员未被记录为线程安全的(例如 Position ),因此您需要确保您只能从一个线程访问此实例(或对逻辑上属于 MemoryStream 的对象的任何引用)时间。

但是 MemoryStream 未被记录为具有线程亲和性,因此您可以从不同的线程访问一个实例——只要这种访问不是并发的。 p>

线程很难(这个问答不言自明)。

我建议您进行一些并发访问,两个线程都同时访问同一个实例,这偶尔会破坏实例状态的某些方面。

我会确保我保持尽可能简单的锁定(试图变得更加聪明并且限制锁定通常是很难找到错误的原因)并使事情正常进行。在多核系统上进行测试也可能有所帮助。只有在分析显示有可能获得显着净(整个应用程序)增益的情况下,才尝试优化锁定。

关于c# - 不同线程访问 MemoryStream,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2825166/

相关文章:

c# - 无法转换为类型库 - 错误 : Element not found

c# - 如何将现代标签链接 float 到左侧?

c# - 是否有设置阻止未处理的异常对话框显示在我编译的应用程序中?

java - 通知运行在不同对象中的线程

c++ - 如何使用boost来代替user+sys来实时跟踪?

c# - 在多线程应用程序中跟踪任务号

c# - 使用 EF 和 WebApi 将父/子对象序列化为

c# - 如何从匿名列表中删除项目

.net - 是否可以在 .NetCore 应用程序中仅发布某些 appsettings.json

c# - 为我的程序文件夹的所有用户设置写权限