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);
}
}
}
在线程中初始化列表是危险的吗?是否有可能两个线程都可以初始化列表并删除其中一个名称?
所以我想到了三个选择:
答案 0 :(得分:0)
好的,我认为对我的案例最有效的是我使用了锁定声明。
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;}
}
答案 1 :(得分:-1)
对于像这样的简单案例,获得线程安全的最简单方法是使用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
说收集在阅读过程中发生了变化。
因为你真的不知道用户何时会使用该集合,所以你可能会返回获取线程安全的最简单方法是将集合复制到一个数组中并返回它。
如果这不实用(收集到大,...),你必须使用System.Collections.Concurrrent中的类,例如BlockingCollection,但这些更多一些。