2

好的。我想让两个线程运行。当前代码:

    public void foo()
    {      
            lock(this)
            {
                while (stopThreads == false)
                {
                   foreach (var acc in myList)
                   {
                     // process some stuff
                   }
                 }
             }
     }

    public void bar()
    {      
            lock(this)
            {
                while (stopThreads == false)
                {
                   foreach (var acc in myList)
                   {
                     // process some stuff
                   }
                 }
             }
     }

两者都在访问同一个列表,问题是我猜第一个线程“foo”没有释放锁;因为“bar”仅在“foo”完成时才开始。谢谢

4

3 回答 3

3

是的,这就是锁的设计方式。

lock 关键字通过获取给定对象的互斥锁、执行语句然后释放锁来将语句块标记为临界区。

互斥意味着在任何时候最多只能有一个线程持有锁。

锁定这一点是一个坏主意,不鼓励这样做。您应该创建一个私有对象并锁定它。要解决您的问题,您可以锁定两个不同的对象。

private object lockObject1 = new object();
private object lockObject2 = new object();

public void foo()
{      
    lock (lockObject1)
    {
         // ...
    }
}

public void bar()
{      
    lock (lockObject2)
    {
         // ...
    }
}

或者,您可以重复使用相同的锁,但将其移动到循环内,以便每个循环都有机会继续:

while (stopThreads == false)
{
   foreach (var acc in myList)
   {
       lock (lockObject)
       {
           // process some stuff
       }
   }
}

但是,我建议您花一些时间了解正在发生的事情,而不是重新排序代码行,直到它似乎可以在您的机器上运行。编写正确的多线程代码很困难。

为了停止线程,我推荐这篇文章:

于 2010-09-25T11:09:19.190 回答
1
于 2010-09-25T11:34:36.333 回答
0

您遇到的问题是您使用的锁非常粗糙。Foo 和 Bad 基本上都不会同时工作,因为首先开始的人会在 COMPLETE WORK CYCLE 中停止另一个人。

但是,它应该只在它把东西从列表中删除时才锁定。Foreach 在这里不起作用 - 根据定义。您必须建立第二个列表并让每个线程删除顶部项目(锁定时),然后处理它。

基本上:

  • Foreach 不起作用,因为两个线程都将通过 compelte 列表运行
  • 其次,锁必须是细粒度的,因为它们只在需要时才锁定。

在您的情况下,您锁定 foo 只会在 foo 完成时被释放。

于 2010-09-25T11:22:51.827 回答