cri*_*rip 5 .net c# multithreading thread-safety
我有以下情况:
我知道当我们直接公开列表时,我会在枚举时遇到并发修改。
但是,当我调用.ToList()它时,它成为List的一个实例,并使用.NET Framework的Array.Copy函数复制所有项目。
您的意思是,如果脏读没问题,使用这种方法是否安全?
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var container = new Container();
Thread writer = new Thread(() =>
{
for (int i = 0; i < 1000; i++)
{
container.Add(new Item("Item " + i));
}
});
writer.Start();
Thread[] readerThreads = new Thread[10];
for (int i = 0; i < readerThreads.Length; i++)
{
readerThreads[i] = new Thread(() =>
{
foreach (Item item in container.Items)
{
Console.WriteLine(item.Name);
}
});
readerThreads[i].Start();
}
writer.Join();
for (int i = 0; i < readerThreads.Length; i++)
{
readerThreads[i].Join();
}
Console.ReadLine();
}
}
public class Container
{
private readonly IList<Item> _items;
public Container()
{
_items = new List<Item>();
}
public IReadOnlyList<Item> Items
{
get { return _items.ToList().AsReadOnly(); }
}
public void Add(Item item)
{
_items.Add(item);
}
}
public class Item
{
private readonly string _name;
public Item(string name)
{
_name = name;
}
public string Name
{
get { return _name; }
}
}
}
Run Code Online (Sandbox Code Playgroud)
当脏读正常时使用这种方法是否安全?
简单的回答 - 不,不是。
首先,根据定义,该方法并不能保证这一点。即使您查看当前的实现(您不应该这样做),您也会看到它正在使用List<T>接受IEnumerable<T>. 然后它检查ICollection<T>,如果是,使用CopyTo方法或只是迭代可枚举。两者都是不安全的,因为第一个依赖于方法的(未知)实现,CopyTo而第二个将在(标准行为)集合枚举器在Add. 即使来源是一个List<T>并且正在使用Array您提到的方法http://referencesource.microsoft.com/#mscorlib/system/collections/generic/list.cs,d2ac2c19c9cf1d44
Array.Copy(_items, 0, array, arrayIndex, _size);
Run Code Online (Sandbox Code Playgroud)
仍然是不安全的,因为它可能会调用带有_items和_size超出的副本_items.Length,当然会抛出异常。只有当此代码以某种方式以原子方式获取两个成员时,您的假设才会正确,但事实并非如此。
所以,简单的不要那样做。
编辑:以上所有内容都适用于您的具体问题。但是我认为对于您所解释的情况有一个简单的解决方案。如果要求单线程添加/多线程读取可接受的陈旧读取,那么可以通过使用包中的ImmutableList<T>类来实现,System.Collections.Immutable如下所示:
public class Container
{
private ImmutableList<Item> _items = ImmutableList<Item>.Empty;
public IReadOnlyList<Item> Items { get { return _items; } }
public void Add(Item item) { _items = _items.Add(item); }
}
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
3662 次 |
| 最近记录: |