簡體   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