2

我相信这个问题会被问很多次,但我想澄清这个概念。

最近,当两个线程在两个不同的函数中访问同一个列表时,我遇到了一个错误。如果我没有正确的锁定,在什么情况下会导致问题?尽管我在第二个函数中有一个锁并且两个线程不相关,但它们正在操作同一个列表。一个是添加,一个是与一个空列表交换。在什么情况下会捕获异常?请帮忙。

伪代码:

List<SomeClass> list=new List<SomeClass>();

  object mutex=new object();

线程 1 访问此函数并修改列表:

public void Manipulate()
{

  //some operation
  list.add(new SomeClass());

}

线程 2 访问此函数并清除列表:

public void SwapList()
{
   List<SomeClass> cls=new List<SomeClass>();
   try
   {
     while(Thread2.isAlive)
     {
       //some operation
       if(list.Count()>0)
       {
         lock(mutex)
         {
           swap(ref list,ref cls)
         }
       }
     }
  }
  catch(exception ex)
  {
  }
}
public void swap(List<SomeClass> a, List<SomeClass> b)
{
  List<SomeClass> temp=a;
  a=b;
  b=temp;
}
4

2 回答 2

4

如果我没有正确的锁定,在什么情况下会导致问题?

每当您至少有两个线程同时访问数据并且其中至少一个正在写入时。

因此,只要有一些可以从多个线程访问的数据,就应该锁定。而且您需要锁定对该数据的每次访问。

作为替代方案,您可以使用线程安全的数据结构(如 中的集合System.Collections.Concurrent)。如果你这样做,你就不必担心锁定自己,因为结构已经正确(并且有效地)做到了。

于 2013-10-19T00:11:51.550 回答
2

锁定应在您使用后立即开始list

lock(mutex)
{
  if(list.Count()>0)    
  {
     swap(ref list,ref cls)
   }
}

只有所有想要使用它的人都锁定它才会有帮助(线程 1 锁定在哪里?)

编辑:

为了避免竞争,必须锁定线程 1。

public void Manipulate()
{
  lock(mutex)
  {
    //some operation
    list.add(new SomeClass());
  }
}

我认为阅读有关Thread-Safe Collections 的内容可能会对您有所帮助——在这种情况下,您通常可以避免处理锁定自己。

关于捕获异常-在这种特定情况下,我看不到并发情况下没有抛出异常。如果您有一个删除方法,并且您会尝试交换列表中的特定项目,它可能已经发生了。

但是可能会发生其他几个异常,所以我不会放置一个块来捕获任何异常,而只会放置那些我可以处理的异常(吞下异常是不好的做法。)

于 2013-10-18T23:43:51.570 回答