2014-10-16 52 views
0

我在這裏做的是在多線程中通過for-each和index方法導航一個只讀列表。結果看起來線程安全,但我不相信。 有沒有人可以告訴下面的代碼(從只讀列表中讀取)是否線程安全?如果是的話,爲什麼C#只讀列表線程同步

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(); 
    } 
} 
+0

解釋爲什麼你認爲它不是線程安全的。 – 2014-10-17 00:06:36

回答

3

它被認爲是線程安全的有多個線程的List<T>同一實例只讀取如果沒有作家。

線程安全

公共靜態此類型的成員(在Visual Basic中的Shared)都是線程安全的。任何實例成員不保證是線程安全的。

在列表上執行多個讀取操作是安全的,但如果在讀取集合時被修改,則會發生問題。爲確保線程安全,請在讀取或寫入操作期間鎖定收集。要使集合能夠被多個線程訪問以進行讀寫,您必須實現自己的同步。對於具有內置同步的集合,請參閱System.Collections.Concurrent命名空間中的類。對於內在線程安全的替代方法,請參閱ImmutableList類。

強調是我的。

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

+0

[ReaderWriterLock](http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlock%28v=vs.110%29.aspx)或[ReaderWriterLockSlim](http://msdn.microsoft.com/zh-CN/)。 com/en-us/library/system.threading.readerwriterlockslim%28v = vs.110%29.aspx)對於具有這種行爲的對象來說是非常有用的工具。它會允許無限的讀者,直到有人想寫,然後阻止寫,直到所有的讀者完成(也阻止新的讀者),讓作家做的工作,然後暢通等待的讀者。 – 2014-10-16 23:15:12

0

如果無人改變列表爲什麼會不會是線程安全的?我在這裏看到的唯一問題是如果(你是超人)並且你按下鍵的速度比線程讀取列表的速度還要快,然後其中一些會被主體殺死。
所以最好等主要完成前完成。

0

如果它沒有被記錄爲線程安全的,那麼不要假設它是!

我給你說明了爲什麼你不應該假設它,除非它被證明的例子:

假設內部,該名單是節點的鏈表,包含具有值的字符串的每個節點。 搜索方法(字符串值)必須迭代節點以查找值是否存在。 顯然這裏沒有線程安全問題。

但是,現在想象一下,爲了一個性能優化的原因,List保留了一個內部數組,其中最後一次搜索的值被寫入,這對於立即檢查最常用的搜索值很有用。

你看到我們在這裏做了什麼?現在讀取會更改列表的內部狀態,並且突變不是線程安全的。

通常情況下,數據結構不會在讀取上發生突變,但除非有記錄,否則不能依賴這些突變!

在名單使用的這種特殊情況下,在MSDN說,前面已經提到:

它是安全的,對名單進行多次讀取操作,但可能會出現 問題,如果該集合被修改,它的正在閱讀。 爲確保線程安全,請在讀取或寫入操作期間鎖定收集。要使集合能夠被多個線程 讀取和寫入,您必須實現自己的同步。 對於具有內置同步的集合,請參閱 System.Collections.Concurrent命名空間中的類。對於固有線程安全的 替代方法,請參閱ImmutableList類。

給出的是,你可以在線程安全的方式下進行多次讀取但不寫入,但不要假設它沒有記錄。

如果你只想使用List來讀取,我建議你用一個僅在列表中公開只讀操作的類來包裝它,這將確保沒有任何代碼偶然地改變列表。