2017-06-22 39 views
0

我一直在開發多線程算法,我對C#中的線程之間共享類成員存在一些疑問。C#:在線程之間共享類成員

我們假設我們有兩個類Algorithm和Processor。處理器有一個 主要方法DoWork和其他可用資源方法偶爾調用以更改可用資源的數量進行處理。 方法運行UpdateResources算法對象由兩個不同的線程調用,可能在不同核心上的工作。

是否有可能是_processor變量將被存儲在CPU的緩存,絕不會被上傳到內存中,並AvaliableResources將永遠不會被調用,因爲_processor是空的第二個線程?

class Processor 
{ 

    public void DoWork() { ... } 
    public void AvaliableResources(int x) { ... } 
} 

class Algorithm 
{ 
    private Processor _processor; 

    public void Run() 
    { 
     _processor = new Processor(); 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     _processor?.AvaliableResources(x); 
    } 
} 

如果有一個同步的問題將下面的代碼是爲它的解決方案?

替代1

class Processor 
{ 
    public void DoWork() { ... } 
    public void UpdateResources(int x) { ... } 
} 

class Algorithm 
{ 
    private volatile Processor _processor; // added volatile keyword 

    public void Run() 
    { 
     _processor = new Processor(); 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     _processor?.UpdateResources(x); 
    } 
} 

替代2

class Processor 
{ 
    public void DoWork() { ... } 
    public void UpdateResources(int x) { ... } 
} 

class Algorithm 
{ 
    private Processor _processor; 

    public void Run() 
    { 
     _processor = new Processor(); 
     Thread.MemoryBarrier(); // Added memory barier 
     _processor.DoWork(); 
     _processor = null; 
    } 

    public void UpdateResources(int x) 
    { 
     Thread.MemoryBarrier(); // Added memory barier 
     _processor?.UpdateResources(x); 
    } 
} 

編輯: 正如您在留言建議,請參閱更好地解釋代碼:

class Processor 
    { 
     private int resources = Environment.ProcessorCount; 

     public void DoWork() 
     { 
      /*do some long running job using avaliable resources*/ 
     } 

     public void UpdateResources(int x) 
     { 
      resources = x; 
     } 
    } 

    class Algorithm 
    { 
     private volatile Processor _processor; 

     public void Run() 
     { 
      _processor = new Processor(); 
      _processor.DoWork(); 
      _processor = null; 
     } 

     public void UpdateResources(int x) 
     { 
      _processor?.UpdateResources(x); 
     } 
    } 

    class Program 
    { 
     static void Main(string[] args) 
     { 
      var algorithm = new Algorithm(); 
      var result = Task.Run(() => algorithm.Run()); 
      // The resources were required for other staff and are reduced 
      algorithm.UpdateResources(1); 
      // The resources are reassigned for the long running algorithm 
      algorithm.UpdateResources(10); 
      // wait until the algorithm finishes 
      result.Wait(); 
      // this update should have no effect as the Run method has finished and _processor is null 
      algorithm.UpdateResources(10); 
     } 
    } 
+0

當你運行代碼時發生了什麼? – Fabulous

+0

另外考慮如果https://stackoverflow.com/questions/3556351/why-we-need-thread-memorybarrier沒有解決您的查詢 – Fabulous

+0

「的第二個線程」 - 既不是線程是第一或第二個 - 他們只是不同的線程;在「Run」甚至被調用之前,「第二個」線程可以完成它所需的一切......在這種情況下:「_processor」的值是多少? –

回答

0

如果您希望以這種方式訪問​​__processor obj,則2選項是錯誤的。

以任何方式,你應該在處理器null,因爲DoWork的運行,並更快地完成。 嘗試查找與睡眠相同的第一個線程,並檢查是否可用已執行。

您的代碼沒有提供足夠的信息來建議正確的方法。

是正確使用volatile關鍵字,但如果運行速度快可以不叫永遠

編輯

好,很好的例子。但問題是執行UpdateResources之前Run Run的主要工作人員。

如果您希望UpdateResources在等待之前執行兩次,您會在等待後插入執行_processor= null的新方法。 以某種方式每一個這樣的代碼,每次您在等待之前調用UpdateResources,您的風險是_processor爲null。

取決於你在等待之前想要什麼

+1

'volatile'是一個非常微妙和細微的野獸;大多數人認爲「volatile」的「效應」實際上只是次要副作用和實現細節。要求任何人定義'volatile'*實際上意味着什麼*,以及這對特定情況有何幫助,......是的,除了少數CPU專家外,大多數人無法給出一個好答案。我把自己包括在「無法給出一個好答案」的組中。 –

+0

我不明白你想用這個線程做什麼。如果你想爲你的問題或其他問題的提示。易失性用於變量中總是最新的更新值。此關鍵字與編譯器交流以優化多線程訪問的值。無論如何,如果運行完成,代碼不會執行更新資源。只有在執行doWork時調用方法更新資源 – Pasalino

+0

@Pasalino我已經添加了更好的示例,我希望它會有所幫助。 –