C# 数组线程安全吗?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1460634/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are C# arrays thread safe?
提问by Gary
In particular
特别是
- Create a function to take an array and an index as parameters.
- Create a n element array.
- Create a n count loop.
- Inside the loop on a new thread assign a new instance of the object to the array using the indexer passed in.
- 创建一个函数以将数组和索引作为参数。
- 创建一个元素数组。
- 创建一个计数循环。
- 在新线程的循环内,使用传入的索引器将对象的新实例分配给数组。
I know how to manage the threads etc. I am interested in know if this is thread safe way of doing something.
我知道如何管理线程等。我有兴趣知道这是否是线程安全的做某事的方式。
class Program
{
// bogus object
class SomeObject
{
private int value1;
private int value2;
public SomeObject(int value1, int value2)
{
this.value1 = value1;
this.value2 = value2;
}
}
static void Main(string[] args)
{
var s = new SomeObject[10];
var threads = Environment.ProcessorCount - 1;
var stp = new SmartThreadPool(1000, threads, threads);
for (var i = 0; i < 10; i++)
{
stp.QueueWorkItem(CreateElement, s, i);
}
}
static void CreateElement(SomeObject[] s, int index)
{
s[index] = new SomeObject(index, 2);
}
}
采纳答案by Jon Skeet
I believe that if each thread only works on a separate part of the array, all will be well. If you're going to sharedata (i.?e. communicate it between threads) then you'll need some sort of memory barrier to avoid memory model issues.
我相信如果每个线程只在数组的一个单独部分上工作,一切都会好起来的。如果您要共享数据(即在线程之间进行通信),那么您将需要某种内存屏障来避免内存模型问题。
I believethat if you spawn a bunch of threads, each of which populates its own section of the array, then wait for all of those threads to finish using Thread.Join
, that that will do enough in terms of barriers for you to be safe. I don't have any supporting documentation for that at the moment, mind you?...
我相信,如果您生成一堆线程,每个线程都填充其自己的数组部分,然后等待所有这些线程完成使用Thread.Join
,那么就屏障而言,这足以保证您的安全。我目前没有任何支持文件,介意吗?...
EDIT: Your sample code is safe. At no time are two threads accessing the same element - it's as if they each have separate variables. However, that doesn't tend to be useful on its own. At some point normally the threads will want to share state - one thread will want to read what another has written. Otherwise there's no point in them writing into a shared array instead of into their own private variables. That'sthe point at which you need to be careful - the coordination between threads.
编辑:您的示例代码是安全的。任何时候都不会有两个线程访问同一个元素——就好像它们每个都有单独的变量一样。但是,这本身并没有什么用处。在某些时候,线程通常会想要共享状态——一个线程会想要读取另一个线程所写的内容。否则,他们写入共享数组而不是写入自己的私有变量是没有意义的。这就是您需要小心的点 - 线程之间的协调。
回答by Joren
MSDN documentation on Arrayssays:
Public static (Shared in Visual Basic) members of this type are thread safe. Any instance members are not guaranteed to be thread safe.
This implementation does not provide a synchronized (thread safe) wrapper for an Array; however, .NET Framework classes based on Array provide their own synchronized version of the collection using the SyncRoot property.
Enumerating through a collection is intrinsically not a thread-safe procedure. Even when a collection is synchronized, other threads can still modify the collection, which causes the enumerator to throw an exception. To guarantee thread safety during enumeration, you can either lock the collection during the entire enumeration or catch the exceptions resulting from changes made by other threads.
此类型的公共静态(在 Visual Basic 中为共享)成员是线程安全的。不保证任何实例成员都是线程安全的。
此实现不为 Array 提供同步(线程安全)包装器;但是,基于 Array 的 .NET Framework 类使用 SyncRoot 属性提供自己的集合同步版本。
通过集合进行枚举本质上不是线程安全的过程。即使在同步集合时,其他线程仍然可以修改集合,这会导致枚举器抛出异常。为了保证枚举期间的线程安全,您可以在整个枚举期间锁定集合或捕获其他线程所做更改导致的异常。
So no, they're not thread safe.
所以不,它们不是线程安全的。
回答by Daniel
Generally when a collection is said to be 'not threadsafe' that means that concurrent accesses could fail internally (e.g. it not safe to read the first element of List<T> while another thread adds an element at the end of the list: the List<T> might resize the underlying array and the read access might go to the new array before the data was copied into it).
通常,当一个集合被称为“非线程安全”时,这意味着并发访问可能会在内部失败(例如,读取 List<T> 的第一个元素是不安全的,而另一个线程在列表的末尾添加了一个元素:List <T> 可能会调整底层数组的大小,并且在将数据复制到新数组之前,读取访问可能会转到新数组)。
Such errors are impossible with arrays because arrays are fixed-size and have no such 'structure changes'. An array with three elements is no more or less thread-safe than three variables.
这种错误对于数组是不可能的,因为数组是固定大小的并且没有这样的“结构变化”。一个包含三个元素的数组与三个变量的线程安全性差不多。
The C# specification doesn't say anything about this; but it is clear if you know IL and read the CLI specification - you could get a managed reference (like those used for C# "ref" parameters) to an element inside an array and then do both normal and volatile loads and stores to it. The CLI spec describes the thread-safety guarantees for such loads and stores (e.g. atomicity for elements <=32 bit)
C# 规范对此没有任何说明;但很明显,如果您了解 IL 并阅读 CLI 规范 - 您可以获得对数组内元素的托管引用(如用于 C#“ref”参数的引用),然后对其执行正常和易失性加载和存储。CLI 规范描述了此类加载和存储的线程安全保证(例如元素 <=32 位的原子性)
So if I'm unterstanding your question correctly, you want to fill an array using different threads, but will assign to each array element only once? If so, that's perfectly thread-safe.
因此,如果我正确理解您的问题,您想使用不同的线程填充数组,但只会分配给每个数组元素一次?如果是这样,那是完全线程安全的。
回答by Eric
The example you are providing is very similar to the way that Microsoft's own Parallel extensions to C# 4.0 work.
您提供的示例与 Microsoft 自己的 C# 4.0 并行扩展的工作方式非常相似。
This for loop:
这个 for 循环:
for (int i = 0; i < 100; i++) {
a[i] = a[i]*a[i];
}
becomes
变成
Parallel.For(0, 100, delegate(int i) {
a[i] = a[i]*a[i];
});
So, yes, your example should be OK. Here's an older blog postabout the new parallel support in C#.