如何在2个线程之间访问共享资源?

时间:2010-06-30 13:52:32

标签: c# multithreading

在Outlook的一个插件中,我有一个工作线程进行一些处理,然后更新一个布尔标志。主线程检查此标志,如果这是假的,它只处理一个while循环并且什么都不做。

 
//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之前进入这段代码,则主线程继续处理循环,而第二线程只是暂停。由于isDone标志永远不会设置为true,因此主线程不做任何事情。

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

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

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

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

1 个答案:

答案 0 :(得分:2)

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

首先我可以建议

while(!isDone)

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

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

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

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

你需要对多线程设计非常小心 - 它们是错综复杂的,并且可能具有模糊和难以预测的行为(但在适当的情况下非常值得做。)