带有列表属性的线程
本文关键字:线程 属性 列表 | 更新日期: 2023-09-27 18:10:54
public static class People
{
List<string> names {get; set;}
}
public class Threading
{
public static async Task DoSomething()
{
var t1 = new Task1("bob");
var t2 = new Task1("erin");
await Task.WhenAll(t1,t2);
}
private static async Task Task1(string name)
{
await Task.Run(() =>
{
if(People.names == null) People.names = new List<string>();
Peoples.names.Add(name);
}
}
}
在线程中初始化列表有危险吗?是否有可能两个线程都可以初始化列表并删除其中一个名称?
所以我在考虑三个选择:
- 让它这样,因为它是简单的-只有当它是安全的,虽然
- 做相同的代码,但使用concurrentBag -我知道线程安全,但初始化安全
- 使用[DataMember(EmitDefaultValue = new List())],然后在Task1中添加,不用担心初始化。但唯一的缺点是有时根本不需要使用列表,每次初始化它似乎是一种浪费。
我认为最适合我的方法是使用lock语句。
public class Class1
{
private static Object thisLock = new Object();
private static async Task Task1(string name)
{
await Task.Run(() =>
{
AddToList(name);
}
}
private static AddToList(string name)
{
lock(thisLock)
{
if(People.names == null) People.names = new List<string>();
People.names.Add(name);
}
}
}
public static class People
{
public static List<string> names {get; set;}
}
对于这样一个简单的情况,获得线程安全的最简单方法是使用lock
语句:
public static class People
{
static List<string> _names = new List<string>();
public static void AddName(string name)
{
lock (_names)
{
_names.Add(name);
}
}
public static IEnumerable<string> GetNames()
{
lock(_names)
{
return _names.ToArray();
}
}
}
public class Threading
{
public static async Task DoSomething()
{
var t1 = new Task1("bob");
var t2 = new Task1("erin");
await Task.WhenAll(t1,t2);
}
private static async Task Task1(string name)
{
People.AddName(name);
}
}
当然它不是很有用(为什么不直接添加线程)-但我希望你能明白。
如果你不使用某种锁,并且并发地读写List
,你很可能会得到一个InvalidOperationException
,表示在读取期间集合发生了变化。
因为你不知道用户什么时候会使用这个集合,所以你可能会返回获得线程安全的最简单的方法是将这个集合复制到一个数组中并返回this。
如果这是不实际的(集合到大,…),你必须使用类在system . collections . concurrent,例如BlockingCollection,但这些有点复杂