繁体   English   中英

C# 数组线程安全吗?

[英]Are C# arrays thread safe?

特别是

  1. 创建一个函数以将数组和索引作为参数。
  2. 创建一个元素数组。
  3. 创建一个计数循环。
  4. 在新线程的循环内,使用传入的索引器将对象的新实例分配给数组。

我知道如何管理线程等。我有兴趣知道这是否是线程安全的做某事的方式。

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

我相信如果每个线程只在数组的一个单独部分上工作,一切都会好起来的。 如果您要共享数据(即在线程之间进行通信),那么您将需要某种内存屏障来避免内存模型问题。

相信,如果你产生一堆线程,每个线程填充它自己的数组部分,然后等待所有这些线程使用Thread.Join完成,这在屏障方面足以让你安全. 我目前没有任何支持文件,请注意......

编辑:您的示例代码是安全的。 任何时候都不会有两个线程访问同一个元素——就好像它们每个都有单独的变量一样。 但是,这本身并没有什么用处。 在某些时候,线程通常会想要共享状态——一个线程会想要读取另一个线程所写的内容。 否则,他们写入共享数组而不是写入自己的私有变量是没有意义的。 这就是您需要小心的点 - 线程之间的协调。

关于阵列的 MSDN 文档说:

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

此实现不为 Array 提供同步(线程安全)包装器; 但是,基于 Array 的 .NET Framework 类使用 SyncRoot 属性提供自己的集合同步版本。

通过集合进行枚举本质上不是线程安全的过程。 即使在同步集合时,其他线程仍然可以修改集合,这会导致枚举器抛出异常。 为了保证枚举期间的线程安全,您可以在整个枚举期间锁定集合或捕获其他线程所做更改导致的异常。

所以不,它们不是线程安全的。

通常,当一个集合被称为“非线程安全”时,这意味着并发访问可能会在内部失败(例如,读取 List<T> 的第一个元素是不安全的,而另一个线程在列表的末尾添加了一个元素:List <T> 可能会调整底层数组的大小,并且在将数据复制到新数组之前,读取访问可能会转到新数组)。

这种错误对于数组是不可能的,因为数组是固定大小的并且没有这样的“结构变化”。 一个包含三个元素的数组与三个变量的线程安全性差不多。

C# 规范对此没有任何说明; 但很明显,如果您了解 IL 并阅读 CLI 规范 - 您可以获得对数组内元素的托管引用(如用于 C#“ref”参数的引用),然后对其执行正常和易失性加载和存储。 CLI 规范描述了此类加载和存储的线程安全保证(例如元素 <=32 位的原子性)

因此,如果我正确理解您的问题,您想使用不同的线程填充数组,但只会分配给每个数组元素一次? 如果是这样,那是完全线程安全的。

您提供的示例与 Microsoft 自己的 C# 4.0 并行扩展的工作方式非常相似。

这个 for 循环:

for (int i = 0; i < 100; i++) { 
  a[i] = a[i]*a[i]; 
}

变成

Parallel.For(0, 100, delegate(int i) { 
  a[i] = a[i]*a[i]; 
});

所以,是的,你的例子应该没​​问题。 这是一篇关于 C# 中新的并行支持的旧博客文章

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM