不是线程安全的 - 公共静态列表<t> </t>

时间:2011-11-19 20:33:46

标签: c# multithreading thread-safety

我在MSDN中读到,当用作公共静态类型时,List是线程安全的。但是,以下代码片段证明了其他情况。我试图添加和删除列表中的元素,但删除方法中途抛出一个错误说索引超出范围。这里出了什么问题?

这是检查我的理论的正确实现吗?如果没有,有人可以建议一个更好的例子。

class Program
{
    public static List<string> strlist = new List<string>();
    public static AutoResetEvent autoEvent = new AutoResetEvent(false);
    static void Main(string[] args)
    {

        strlist = new List<string>();
        new Thread(() => 
        {

            for(int i=0;i<10000000;i++)
            {
         strlist.Add("item1");
            }
            //Thread.Sleep(5000);
            autoEvent.Set();
        }).Start(); ;

        new Thread(() => {

         strlist.ForEach(e => strlist.Remove(e));

        }).Start();

        Console.WriteLine("Waiting");
        autoEvent.WaitOne();
        int ci = 0;

        strlist.ForEach(str => ci++);
        Console.WriteLine(ci.ToString() + " Done");
        Console.Read();


    }

}

3 个答案:

答案 0 :(得分:12)

  

我在MSDN中读到,当用作公共静态类型时,List是线程安全的。

这种说法不正确。你可能指的是这个文字:

  

此类型的公共静态成员是线程安全的。

指的是班级List<T>成员。它引用类List<T>实例

答案 1 :(得分:9)

你的阅读不正确。您正在使用实例成员(.Add()等);实例成员线程安全; MSDN is explicit about this.

  

线程安全

     

此类型的公共静态(在Visual Basic中为Shared)成员是线程安全的。不保证任何实例成员都是线程安全的。

     

只要未修改集合,List<T>可以同时支持多个阅读器。枚举通过集合本质上不是线程安全的过程。在枚举与一个或多个写访问争用的极少数情况下,确保线程安全的唯一方法是在整个枚举期间锁定集合。要允许多个线程访问集合以进行读写,您必须实现自己的同步。

事实上,List<T> 没有任何静态方法(文本只是断言默认值:静态成员通常是线程安全的;实例成员通常不是线程的 - 安全的)

答案 2 :(得分:1)

我认为当他们说“静态”时,他们并不意味着你必须使用 static 关键字,一切正常。它们意味着只要列表是静态的,就像“它永远不会以任何方式被修改”那么你可以从多个线程中使用它而没有任何问题。