【问题标题】:how to access shared resource between 2 threads?如何访问2个线程之间的共享资源?
【发布时间】:2011-03-10 03:47:57
【问题描述】:

在 Outlook 插件之一中,我有一个工作线程,它进行一些处理,然后更新一个布尔标志。主线程检查这个标志,如果它是 false ,它只是处理一个 while 循环而不做任何事情。

//工作线程 无效 DoSoneThing() { Outlook.Recipients recps = mail.Recipients。 foreach(recps 中的 Outlook.Recipient recp) { //将每个收件人保存在一个集合中 } 完成=真; } //主线程 而(!完成) { //读取已存储收件人姓名的集合。 }``

如果主线程在工作线程将标志设置为 true 之前到达这段代码,则主线程继续处理循环,辅助线程只是暂停。并且由于 isDone 标志永远不会设置为 true,因此主线程不会做任何事情。

当我在 DoSomeThing 方法中加一个锁并在 mian 线程中使用相同的锁时,这个问题就解决了。

我的课 { 公共静态对象 _syncRoot = new Object(); 无效 DoSoneThing() { 锁(_syncRoot) { //过程 完成=真; } } } 我的其他类 { 锁定(myClass._syncRoot) { //过程 } }

我的理解是锁用于限制多个线程对同一段代码的访问。但是不明白为什么主线程访问共享资源时工作线程不做任何事情。

【问题讨论】:

  • 你跳过了所有重要的逻辑。请发布 Main 和 DoSomething 的实现。

标签: c# multithreading


【解决方案1】:

我认为这里可能存在一个轻微的概念问题。

首先我可以建议

while(!isDone)

不是一种很好的等待方式——它被称为“旋转”,它允许线程在它不做任何事情时使用处理器时间,这不是有效的。 (在某些特定情况下旋转锁是可以的,但在用户应用中通常不是一个好计划。)

锁,让一个线程等待,而其他进程要好得多。

现在,至于您的具体问题。在 while 测试中读取的 isDone 标志可能已被优化(即编译器“知道”它不会改变,因此它不会放入任何代码以再次从内存中获取它 - 它只是测试相同的 CPU 寄存器。)您可以通过使用 'volatile' 修饰符来告诉编译器它必须从内存中重新获取值来克服这个问题。 也有可能是主线程在旋转,正在使另一个线程挨饿,因此它永远没有机会设置标志(尽管人们希望它最终会在一个“公平”的系统中。)

无论后者如何,都应避免在等待另一个线程完成处理时出现线程自旋,除非检查了标志,否则它会转而做一些有用的事情(例如更新 GUI)。

您需要非常小心多线程设计 - 它们错综复杂,并且可能具有晦涩难懂且难以预测的行为(但在适当的情况下非常值得这样做。)

【讨论】:

  • 谢谢拉格斯特。我知道这不是一个好的设计,我会努力的。我同意你的第一个理由,我会检查 volatile。但是由于后一个原因,如果邮件线程饿死了另一个线程,那么当我使用锁而不是自旋循环时它是如何开始工作的呢?
  • 嗨卡皮尔格。当您使用 Lock 时,您让操作系统知道没有访问权限的线程应该等待访问 - 即线程变得不可调度,并且 Windows 不会为其分配任何处理器时间。在那种情况下,它不会饿死另一个线程,因为它被挂起。这有意义吗?
猜你喜欢
  • 1970-01-01
  • 2010-12-18
  • 1970-01-01
  • 2012-04-07
  • 1970-01-01
  • 1970-01-01
  • 2023-03-10
  • 1970-01-01
相关资源
最近更新 更多