使用List属性进行线程处理

时间:2014-07-01 12:44:55

标签: c# .net thread-safety task

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

在线程中初始化列表是危险的吗?是否有可能两个线程都可以初始化列表并删除其中一个名称?

所以我想到了三个选择:

  1. 保持这样,因为它很简单 - 只有它是安全的
  2. 执行相同的代码但使用concurrentBag - 我知道线程安全但是初始化安全
  3. 使用[DataMember(EmitDefaultValue = new List())],然后在Task1中执行.Add,而不用担心初始化。但对此唯一的看法是有时列表根本不需要使用,每次初始化它似乎都是浪费。

2 个答案:

答案 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,但这些更多一些。