2011-03-02 34 views
1


有趣的是,我要測試墓碑和併發性,並且在我簡單的設置過程中,我想到了什麼是真的,是否真的值得麻煩。但是現在,在設置了一些愚蠢的測試課程45分鐘後,我遇到了第一個我不明白的錯誤。WP7(C#)的簡單鎖定和ThreadPoolQuestion

似乎我需要在列表,鎖和線程中多做點練習。有沒有人知道爲什麼會引發非法操作異常(請參閱附件代碼)。

一個誰喜歡F5體驗更好,這裏是完整的解決方案(300KB)
http://www.filesavr.com/TXXXFVE40GTJK43

不要打開的意見,他們可能會崩潰的VS2010。而且你需要WP7工具,對不起,即使我很確定這個例子也可以在純C#上工作(不工作)。

[編輯] 我更新鏈接,現在它正在(與老代碼)
我發現的第一個錯誤,感謝評論。

這工作:

private void IncOneWithLock() 
    { 
     lock (CounterListOne) 
     { 
      IncListOne(); 
     } 
    } 

    private void IncListOne() 
    { 
     if (CounterListOne == null) 
     { 
      Log("CounterListOne == null"); 
      return; 
     } 

     var c = 0; 
     var oldList = CounterListOne.ToList(); 
     foreach (var i in oldList) 
     { 
      CounterListOne[c++] = i + 1; 
      Thread.Sleep(Next(80*DelayFactor, 150*DelayFactor)); 
     } 
    } 

將繼續測試立碑的東西,可能後問題在以後的線程。更改列表而迭代 - 你好新手的錯誤:-)

[/編輯]

爲了您conveniece的厚望發生在這個功能,其操作無效厚望:

private void IncOneWithLock() 
    { 
     if (CounterListOne == null) 
     { 
      Log("CounterListOne == null"); 
      return; 
     } 

     lock (this) 
     { 
      var c = 0; 
      foreach (var i in CounterListOne) 
      { 
       CounterListOne[c++] = i + 1; 
       Thread.Sleep(Next(80 * DelayFactor, 150 * DelayFactor)); 
      } 
     } 
    } 

以下是測試課程的完整來源:

public class CounterClass : TestBase 
{ 
    private DispatcherTimer _dT; 
    public int CounterA { get; set; } 

    public ObservableCollection<int> CounterListOne { get; set; } 
    public List<int> CounterListTwo { get; set; } 
    public List<int> CounterListThree { get; set; } 
    private const int DelayFactor = 10; 


    public CounterClass() 
    { 
     CounterListOne = new ObservableCollection<int>(); 
     CounterListTwo = new List<int>(); 
     CounterListThree = new List<int>(); 

     InitCounterLists(); 
     StartBackgroundLogger(); 
    } 

    public void LogLists() 
    { 
     lock (this) 
      //lock (CounterListTwo) 
      // lock (CounterListThree) 
       { 
        Log("===================================================="); 
        Log("CounterListOne " + String.Join("-", CounterListOne.Select(x => x.ToString()).ToArray())); 
        Log("CounterListTwo " + String.Join("-", CounterListTwo.Select(x => x.ToString()).ToArray())); 
        Log("CounterListThree " + String.Join("-", CounterListThree.Select(x => x.ToString()).ToArray())); 
        Log("===================================================="); 
       } 
    } 

    public void RunTests() 
    { 
     Log("MultiIncWithoutLocks"); 
     //MultiIncWithoutLocks(); 

     Log("MultiIncWithLocks"); 
     MultiIncWithLocks(); 
    } 

    public void MultiIncWithoutLocks() 
    { 
     ThreadPool.QueueUserWorkItem(x => IncOneWithoutLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithoutLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithoutLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithoutLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithoutLock()); 
    } 

    public void MultiIncWithLocks() 
    { 
     ThreadPool.QueueUserWorkItem(x => IncOneWithLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithLock()); 
     ThreadPool.QueueUserWorkItem(x => IncOneWithLock()); 
    } 

    private void IncOneWithoutLock() 
    { 
     var c = 0; 
     foreach (var i in CounterListOne) 
     { 
      CounterListOne[c++] = i+1; 
      Thread.Sleep(Next(80 * DelayFactor, 150 * DelayFactor)); 
     } 
    } 

    private void IncOneWithLock() 
    { 
     if (CounterListOne == null) 
     { 
      Log("CounterListOne == null"); 
      return; 
     } 

     lock (this) 
     { 
      var c = 0; 
      foreach (var i in CounterListOne) 
      { 
       CounterListOne[c++] = i + 1; 
       Thread.Sleep(Next(80 * DelayFactor, 150 * DelayFactor)); 
      } 
     } 
    } 

    private void InitCounterLists() 
    { 
     InitCounterOne(); 
     InitCounterTwo(); 
     InitCounterThree(); 
    } 


    private void InitCounterOne() 
    { 
     for (int i = 0; i < Next(1, 5); i++) 
     { 
      CounterListOne.Add(0); 
     } 
    } 

    private void InitCounterTwo() 
    { 
     for (int i = 0; i < Next(1, 5); i++) 
     { 
      CounterListTwo.Add(0); 
     } 
    } 

    private void InitCounterThree() 
    { 
     for (int i = 0; i < Next(1, 5); i++) 
     { 
      CounterListThree.Add(0); 
     } 
    } 

    private void StartBackgroundLogger() 
    { 
     _dT = new DispatcherTimer(); 
     _dT.Tick += (a,b) => LogLists(); 
     _dT.Interval = new TimeSpan(0,0,0,3); 
     _dT.Start(); 
    } 


} 
+1

錯誤消息,堆棧轉儲,行號?代碼_does_的哪部分被執行? – 2011-03-02 09:58:47

+0

您的鏈接項目丟失 – 2011-03-02 10:00:39

回答

3

您應該提供有關該例外的更詳細說明。它與foreach和CounterListOne連接:在迭代其值時得到它,結果爲InvalidOperationException

+0

謝謝,更新了代碼和鏈接,現在正在工作。馬上會尋找新的問題:-) – 2011-03-02 10:18:17

0

你正在使用observable集合來綁定你的視圖嗎?
這裏發生的事情是,通過更新observablecollection中的值,您希望通過非UI線程來更新UI,從而導致您的異常。是您使用Dispatcher.BeginInvoke更新值而不是將工作

Dispatcher.BeginInvoke(() => { // This code is on the UI thread. });

不幸的是,這將排序或測試的廢墟一部分,因爲它卸載所有的值更新活動回到UI。解決這個問題的方法是創建一個自定義的Iobservable元素。您可以在需要時存儲和更新該對象中的值,並在需要時手動調用它的事件(通過Dispatcher.BeginInvoke)。至少將價值更新完全放在單獨的線程上。但是由於Silverlight可視化的安排方式,您永遠無法從單獨的線程更新UI

+0

謝謝,其實我覺得我的錯誤更簡單,但我意識到你描述的這個問題。我將把它包含在另一個測試類中,並且已經存在一些問題。 – 2011-03-02 10:31:13

+0

如果將所有這些東西(線程,序列化,邏輯刪除,UI更新)結合起來,就會產生一些問題,這使得它值得進行一些基本測試。我的意思是你現在所有的東西,但是如果你沒有花時間在設計你的解決方案時考慮到所有的問題,那麼以後可能會變得非常混亂...... – 2011-03-02 10:32:54

+0

是的,這是絕對正確的。對於我從中學到的東西,我確信所有的ViewModel都是通過一個單類來驅動的,它確保'Updated'事件總是通過Dispatcher.BeginInvoke(' – 2011-03-02 15:27:10