在线程中的 C# 锁中同时添加和删除列表中的项
本文关键字:删除 删除列 列表 添加 线程 | 更新日期: 2023-09-27 18:35:56
我相信这个问题会被问很多次,但我想弄清楚这个概念。
最近我遇到了一个错误,当两个线程在两个不同的函数中访问同一个列表时。如果我没有正确的锁定,在什么情况下会导致问题?即使我在第二个函数中有一个锁并且两个线程不相关,它们也在操作同一个列表。一个是添加,一个是与空列表交换。在什么情况下会发现异常?请帮忙。
伪代码:
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;
}
如果我没有正确的锁定,在什么情况下会导致问题?
每当至少有两个线程同时访问数据并且其中至少一个线程正在写入时。
因此,只要有一些可以从多个线程访问的数据,就应该锁定。而且您需要锁定对该数据的每次访问。
作为替代方法,您可以使用线程安全的数据结构(如 System.Collections.Concurrent
中的集合)。如果你这样做,你就不必担心锁定自己,因为结构已经正确(和有效地)完成了它。
使用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());
}
}
我认为阅读有关线程安全集合的信息可能会对您有所帮助 - 在这种情况下,您大多可以避免将手柄锁定自己。
关于捕获异常 - 在这种特定情况下,我看不到从并发情况下引发的异常。如果您有删除方法,并且会尝试交换列表中的特定项目,则可能会发生这种情况。
但是可能会发生其他几个异常,所以我不会放置一个捕获任何异常的块,而只会放置我可以处理的块(吞下异常是一种不好的做法。