C#Readonly List线程同步

时间:2014-10-16 23:05:32

标签: c# multithreading synchronization thread-safety

我在这里做的是在多个线程中通过for-each和index方法导航只读列表。结果看起来线程安全,但我不相信。 任何人都可以告诉下面的代码(从只读列表中读取)是否是线程安全的?如果是,那么为什么

 public class ThreadTest
{
   readonly List<string> port;

    public  ThreadTest()
    {
        port = new List<string>() { "1", "2", "3", "4", "5", "6" };            
    }

    private void Print()
    {
        foreach (var itm in port)
        {
            Thread.Sleep(50);
            Console.WriteLine(itm+"----"+Thread.CurrentThread.ManagedThreadId);
        }
    }
    private void Printi()
    {
        for(int i=0;i<5;i++)
        {
            Thread.Sleep(100);
            Console.WriteLine(port[i] + "--iiiii--" + Thread.CurrentThread.ManagedThreadId);
        }
    }

    public void StartThread()
    {
        Task[] tsks = new Task[10];
        tsks[0] = new Task(Print);
        tsks[1] = new Task(Print);
        tsks[2] = new Task(Print);
        tsks[3] = new Task(Print);
        tsks[4] = new Task(Print);
        tsks[5] = new Task(Printi);
        tsks[6] = new Task(Printi);
        tsks[7] = new Task(Printi);
        tsks[8] = new Task(Printi);
        tsks[9] = new Task(Printi);

        foreach (var tsk in tsks)
        {
            tsk.Start();
        }

        Task.WaitAll(tsks);
    }
}

 class Program
{
    static void Main(string[] args)
    {

        new ThreadTest().StartThread();

        Console.ReadLine();
    }
}

3 个答案:

答案 0 :(得分:3)

只有在没有编写器的情况下才允许多个线程从List<T>的同一个实例读取,这被认为是线程安全的。

  

线程安全

     

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

     

对List执行多个读取操作是安全的,但如果在读取时修改了集合,则会出现问题。要确保线程安全,请在读取或写入操作期间锁定集合。要使多个线程可以访问集合以进行读写,您必须实现自己的同步。对于具有内置同步的集合,请参阅System.Collections.Concurrent命名空间中的类。有关本质上线程安全的替代方法,请参阅ImmutableList类。

重点是我的。

http://msdn.microsoft.com/en-us/library/6sh2ey19(v=vs.110).aspx

答案 1 :(得分:0)

如果没有人更改列表,为什么它不是线程安全的?我在这里看到的唯一问题是,如果(你是超人)你按下键比线程读取列表更快,然后其中一些将被主要杀死。
所以最好在主要完成之前等待它们完成。

答案 2 :(得分:0)

如果没有记录为线程安全,那么不要认为它是!

我将举例说明为什么你不应该假设它,除非记录在案:

假设在内部,List是一个LinkedList节点,每个节点都包含一个带有值的字符串。 方法Search(字符串值),必须遍历节点以查找值是否存在。 显然这里没有线程安全问题。

但是现在,想象一下,出于性能优化的原因,List保留了一个内部数组,其中写入了最后搜索的值,这对于立即检查最常搜索的值非常有用。

你看到我们在这里做了什么吗?现在读取会更改列表的内部状态,并且突变不是线程安全的。

通常,数据结构不会对读取进行突变,但除非记录在案,否则不能依赖它!

在List使用的这种特殊情况下,msdn说,如前所述:

  

在List上执行多个读取操作是安全的,但是   如果在读取集合时修改了集合,则可能会出现问题。   为确保线程安全,请在读取或写入期间锁定集合   操作。使多个线程可以访问集合   对于读写,您必须实现自己的同步。   对于具有内置同步的集合,请参阅中的类   System.Collections.Concurrent命名空间。对于固有的线程安全   替代方案,请参阅ImmutableList类。

给出,是的,您可以以线程安全的方式执行多次读取而不进行写入,但除非记录,否则不要假设它。

如果你只想使用List来阅读,我建议你用一个只在列表中公开读操作的类来包装它,这样可以确保没有代码偶然改变列表。