在C#中同时添加和删除列表项-线程锁定

3

我相信这个问题已经被问了很多次,但是我想清楚这个概念。

最近,在两个不同的函数中有两个线程访问同一个列表时,我遇到了一个bug。如果我没有正确的锁定,在什么情况下会出现问题?即使我在第二个函数中有一个锁,并且这两个线程没有关联,它们正在操作同一个列表。其中一个正在添加,另一个正在与空列表交换。在什么情况下会触发异常?请帮忙。

伪代码:

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;
}

虽然这并不回答你的问题,但是在多线程列表中,你应该使用一个并发包。 - undefined
你是指 "isn't" 吗,@svick? - undefined
@MillieSmith 对的,是的,打错了。 - undefined
“在什么情况下会捕获异常?”这不是一个正确的问题,因为异常并不是事情出错的唯一方式。 - undefined
你对多线程的经验还不够,尚未达到可以变得聪明机智的水平。不要尝试过于聪明。 - undefined
2个回答

5

如果我没有正确的锁定,会在什么场景下造成问题?

只要有至少两个线程同时访问数据,且其中至少一个线程正在写入,那就可能会出现问题。

因此,每当您有一些可以从多个线程访问的数据时,都应该进行锁定。并且您需要锁定对该数据的每次访问。

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


+1 是为了 System.Collections.Concurrent 而设立的,它专门用于执行这些锁定操作: https://github.com/dotnet/runtime/blob/main/src/libraries/System.Collections.Concurrent/ref/System.Collections.Concurrent.cs - undefined

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());
  }
}

我认为阅读关于线程安全集合的内容可能会对你有所帮助-在这种情况下,你可以避免大部分自行处理句柄锁定。
关于捕获异常-在这种特定情况下,我看不到并发情况下抛出任何异常。如果你有一个删除方法,并且你尝试交换列表中的特定项,那么可能会发生异常。
但可能会发生其他几个异常,因此我不会放置捕获任何异常的块,而只是我能够处理的异常(吞咽异常是不好的做法)。

Manipulate() 方法中的列表操作也应该被锁定,因为 Manipulate() 可能会被不同线程同时调用。 - user2819245
@elgonzo - 当然。我指的是“线程1在哪里锁定?” - undefined
谢谢你们的解释,但我真正想知道的是,你们能否描述一个可能导致异常的多线程场景。我明白加锁意味着我的列表永远不会被破坏,但这并不会使我的应用程序崩溃。那么,在哪种情况下我可以捕获异常呢?比如说,在catch块中我有这段代码。 - undefined

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接