2014-02-08 53 views
0

問題描述:需要諮詢用於Synchornizing線程

在我的應用程序具有低於類2個線程之間的同步中的一個。

  1. SynchornizingMethods講座>將由線程1和線程共享2.
  2. DemoClass1 - >通過螺紋簡稱1
  3. DemoClass2 - >由線程2
  4. SynchornizingDemo.Demo()簡稱 - >方法是程序的入口點。

預期輸出:

線程1(DemoClass1)和線程2(DemoClass2),直到這兩個線程完成它們的環在各自的XXXXRun()方法應該平行地延伸。

現狀:

程序,當我從我的應用程序調用SynchornizingDemo.Demo()只是掛起。

代碼:

public class SynchornizingMethods 
{ 
    static string SharedVariableString = string.Empty; 

    bool threadFlag = true; 

    public void Method1(int inputVal) 
    { 
     lock (this) 
     { 
      if (threadFlag == true) 
      { 
       try 
       { 
        Monitor.Wait(this); 
       } 
       catch (SynchronizationLockException SLE) 
       { 
        SharedVariableString += "\nMethod 1 : " + SLE.Message.ToString(); 
       } 
       catch (ThreadInterruptedException TIE) 
       { 
        SharedVariableString += "\nMethod 1 : " + TIE.Message.ToString(); 
       } 

       SharedVariableString += "\nMethod 1 : " + inputVal; 
       threadFlag = false; 
      } 

      Monitor.Pulse(this); 
     } 
    } 

    public void Method2(int inputVal) 
    { 
     lock (this) 
     { 
      if (threadFlag == false) 
      { 
       try 
       { 
        Monitor.Wait(this); 
       } 
       catch (SynchronizationLockException SLE) 
       { 
        SharedVariableString += "\nMethod 2 : " + SLE.Message.ToString(); 
       } 
       catch (ThreadInterruptedException TIE) 
       { 
        SharedVariableString += "\nMethod 2 : " + TIE.Message.ToString(); 
       } 

       SharedVariableString += "\nMethod 2 : " + inputVal; 
       threadFlag = true; 
      } 

      Monitor.Pulse(this); 
     } 
    } 

    public static void DisplayResult() 
    { 
     MessageBox.Show(SharedVariableString); 
    } 
} 
public class DemoClass1 
{ 
    SynchornizingMethods SyncMethodsObj; 
    public DemoClass1(SynchornizingMethods _SyncMethodsObj) 
    { 
     SyncMethodsObj = _SyncMethodsObj; 
    } 

    public void DemoThread1Run() 
    { 
     // Even Incrementor.    
     for (int lpCnt = 0; lpCnt <= 20; lpCnt += 2) 
     { 
      //Thread.Sleep(10); 
      SyncMethodsObj.Method1(lpCnt); 
     } 
    } 
} 
public class DemoClass2 
{ 
    SynchornizingMethods SyncMethodsObj; 
    public DemoClass2(SynchornizingMethods _SyncMethodsObj) 
    { 
     SyncMethodsObj = _SyncMethodsObj; 
    } 

    public void DemoThread2Run() 
    { 
     // Odd Incrementor. 
     for (int lpCnt = 1; lpCnt <= 20; lpCnt += 2) 
     { 
      //Thread.Sleep(10); 
      SyncMethodsObj.Method2(lpCnt); 
     } 
    } 
} 

public class SynchornizingDemo 
{ 
    public void Demo() 
    { 
     SynchornizingMethods SyncMethodsObj = new SynchornizingMethods(); 

     DemoClass1 DemoClass1Obj = new DemoClass1(SyncMethodsObj); 
     DemoClass2 DemoClass2Obj = new DemoClass2(SyncMethodsObj); 

     try 
     { 
      Thread thread1Obj = new Thread(new ThreadStart(DemoClass1Obj.DemoThread1Run)); 
      Thread thread2Obj = new Thread(new ThreadStart(DemoClass2Obj.DemoThread2Run)); 

      thread1Obj.Start(); 
      thread2Obj.Start(); 

      thread1Obj.Join(); 
      thread2Obj.Join(); 
     } 
     catch (ThreadStateException TSE) 
     { 
      Debug.WriteLine(" Exception Raised SynchornizingDemo : " + TSE.Message.ToString()); 
     } 
     catch (ThreadInterruptedException TIE) 
     { 
      Debug.WriteLine(" Exception Raised SynchornizingDemo : " + TIE.Message.ToString()); 
     } 

     SynchornizingMethods.DisplayResult(); 
    } 
} 
+1

該代碼「看起來」不完整,當然不會被任何人編譯。你也在說「不按預期工作」 - 它如何工作,你會得到什麼結果。 – iandotkelly

+0

@iandotkelly,是的,它完成的代碼只需要調用SynchornizingDemo.Demo()進行測試,這是我在第一篇文章中提到的,但修改該語句的人被刪除並導致混淆。我已經發布了下面的工作計劃。 – Sai

回答

0

謝謝大家的提示。我解決了這個問題。它與If條件,我只是用兩種方法交換語句。以下是更新的代碼。

基本上以下程序的內涵是2個線程將同步共享公共變量,並通過在Demo類中並行運行兩個循環來更新一個線程。

 
public class SynchornizingMethods 
    { 
     static string SharedVariableString = string.Empty; 

     bool threadFlag = true; 

     public void Method1(int inputVal) 
     { 
      lock (this) 
      { 
       if (!threadFlag) 
       { 
        try 
        { 
         Monitor.Wait(this); 
        } 
        catch (SynchronizationLockException SLE) 
        { 
         SharedVariableString += "\nMethod 1 : " + SLE.Message.ToString(); 
        } 
        catch (ThreadInterruptedException TIE) 
        { 
         SharedVariableString += "\nMethod 1 : " + TIE.Message.ToString(); 
        } 
       } 

       SharedVariableString += "\nMethod 1 : " + inputVal; 
       Debug.WriteLine("Method 1 : " + inputVal); 
       threadFlag = false; 
       Monitor.Pulse(this); 
      } 
     } 

     public void Method2(int inputVal) 
     { 
      lock (this) 
      { 
       if (threadFlag) 
       { 
        try 
        { 
         Monitor.Wait(this); 
        } 
        catch (SynchronizationLockException SLE) 
        { 
         SharedVariableString += "\nMethod 2 : " + SLE.Message.ToString(); 
        } 
        catch (ThreadInterruptedException TIE) 
        { 
         SharedVariableString += "\nMethod 2 : " + TIE.Message.ToString(); 
        } 
       } 
       SharedVariableString += "\nMethod 2 : " + inputVal; 
       Debug.WriteLine("Method 2 : " + inputVal); 
       threadFlag = true; 

       Monitor.Pulse(this); 
      } 
     } 

     public static void DisplayResult() 
     { 
      MessageBox.Show(SharedVariableString); 
     } 
    } 

    public class DemoClass1 
    { 
     SynchornizingMethods SyncMethodsObj; 

     public DemoClass1(SynchornizingMethods _SyncMethodsObj) 
     { 
      SyncMethodsObj = _SyncMethodsObj; 
     } 

     public void DemoThread1Run() 
     { 
      // Even Incrementor.    
      for (int lpCnt = 0; lpCnt
+0

輸出在調試結果:方法1:0 方法2:1 方法1:2 方法2:3 方法1:4 方法2:5 方法1:6 方法2:7 方法1:8 方法2:9 方法1:10 方法2:11 方法1:12 方法2:13 方法1:14 方法2:15 方法1:16 方法2:17 方法1:18方法2:19 線程'CustomThread2'(0x1d54)h如代碼0(0x0)所示。 方法1:20方法2:21 線程'CustomThread1'(0x2b4c)已退出,代碼爲0(0x0)。 是線程1 ActiveFalse 是線程2 ActiveFalse – Sai

0

我覺得你在try塊需要Monitor.Wait(這)之前Monitor.Pulse(本)。 我相信它是阻塞的,因爲一個線程等待鎖並休眠,然後另一個線程休眠而不通知第一個線程鎖已準備就緒。

+0

感謝您的分析,但並非如此,在這種情況下,兩個線程只會在上述程序中運行一次。由於我的錯誤條件,它被阻塞。 – Sai

0

您的代碼是錯誤的。可以考慮在for循環的結束髮生的事情:

1)線索1具有lpCnt等於20threadFlagtrue。它掛在Monitor.Wait

2)線程2有lpCnt等於19threadFlagtrue所以它只是調用Monitor.Pulse

3)線索1修改字符串,並設置threadFlagfalse。因爲這是它的最後一次迭代,所以它完成並存在

4)線程2進入lock。因爲沒有人可以撥打Monitor.Pulse,所以無限期地等待Monitor.Wait

此外,使用Monitor.WaitMonitor.Pulse「對稱」同步兩個線程存在已知問題。 documentation說:

Monitor類不維護狀態,指示已調用Pulse方法。因此,如果在沒有線程正在等待時調用Pulse,則調用Wait的下一個線程阻塞,就像從未調用過Pulse一樣。如果兩個線程正在使用Pulse和Wait進行交互,則可能導致死鎖。將其與AutoResetEvent類的行爲進行對比:如果您通過調用其Set方法發出AutoResetEvent指示,並且沒有線程在等待,則AutoResetEvent將保持信號狀態,直到線程調用WaitOne,WaitAny或WaitAll。 AutoResetEvent釋放該線程並返回到無信號狀態。

+0

首先感謝您的詳細分析。是的,我還注意到您對已知問題強調的一點。不管計數如何,點1 - 4都不會導致程序被掛起而退出線程。我測試了這些步驟並且工作正常。我在if語句中所做的錯誤,我在下面修復併發布了乾淨的代碼。 – Sai

+1

@SrigopalChitrapu - 測試不是解決同步問題的方法。要確定代碼是正確的唯一方法是理解它,因爲在測試時競爭條件可能永遠不會顯示出來。 –

+0

@SrigopalChitrapu第1-4點與這些'if'語句直接相關。如果你改變了他們,並且**似乎**(見上面的Erno的評論)來幫助,那麼我寫的就是這個原因。 – BartoszKP