2010-06-30 105 views
0

在Outlook中添加一个,我有一个工作线程做了一些处理,然后更新布尔标志。主线程检查这个标志,如果这是错误的,它只是处理一个while循环而什么也不做。如何访问2个线程之间的共享资源?

 
//worker thread 
void DoSoneThing() 
{ 
Outlook.Recipients recps = mail.Recipients. 
foreach(Outlook.Recipient recp in recps) 
{ 
//Save each recipients in a colection 
} 
isDone=true; 
} 


//Main thread 
while(!isDone) 
{ 
//read the collection where recipients name have been stored. 
}`` 

如果主线程谈到这段代码的工作线程设置标志为true,主线程之前不断处理回路和secondry线程是正中下怀暂停。并且由于isDone标志从不设置为true,所以主线程不会执行任何操作。

当我在DoSomeThing方法中放入一个锁并在mian线程中使用相同的锁时,此问题已得到解决。

 
myClass 
{ 
public static object _syncRoot = new Object(); 
void DoSoneThing() 
{ 
lock(_syncRoot) 
{ 
//process 
isDone=true; 
} 
} 
} 

myOtherClass 
{ 
    lock(myClass._syncRoot) 
{ 
//process 
} 
} 

我的理解是锁用于限制由一个以上的线程的项,以相同的一段代码。但不明白为什么工作线程在共享资源被主线程访问时没有做任何事情。

+0

你跳过所有的(但非常值得做的正确的情况下)。重要的逻辑。请发布Main和DoSomething的实现。 – 2010-06-30 14:02:05

回答

2

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

首先,我可以建议的

while(!isDone) 

不是等待一个伟大的方式 - 它被称为“旋转”,并允许线程使用处理器的时候,它没有做任何事情,这是没有效率的。 (在某些特定情况下旋转锁可能会有问题,但在用户应用程序中通常不是一个好计划。)

锁,使一个线程等待,而其他进程更好。

现在,至于你的具体问题。在while测试已经被优化的情况下读取isDone标志是可能的(例如,编译器'知道'它不会改变,所以它不会放入任何代码来再次从内存中获取它 - 它只是测试相同的CPU寄存器)。您可以通过使用'volatile'修饰符来告诉编译器必须从内存中重新获取值,从而克服这一点。 也可能是主线程正在旋转,从而导致另一个线程不能正常工作(尽管人们希望它最终会在一个'公平'系统中运行)。

无论后者,在等待另一个线程完成处理时有一个线程旋转是应该避免的,除非检查了该标志,否则它会转而执行一些有用的操作(例如更新GUI)。

你必须要非常小心多线程的设计 - 他们是复杂的,可以有晦涩和难以预知的行为

+0

谢谢拉格斯特。我知道这不是一个好的设计,我会继续努力。我同意你的第一个理由,我会去检查易变的。但由于后一个原因,如果邮件线程使另一个线程饿死,那么当我使用锁定而不是旋转循环时,它是如何开始工作的? – Kapil 2010-06-30 15:06:56

+0

嗨Kapilg。当你使用Lock时,你让操作系统知道没有访问权限的线程应该等待访问 - 这就是线程变得不可调度,并且Windows不会为它分配任何处理器时间。在那种情况下,它不会因为暂停而使其他线程陷于饥饿。那有意义吗? – Ragster 2010-06-30 15:36:24

+0

绝对:) :) – Kapil 2010-06-30 15:43:50