2014-06-11 93 views
0

我嘗試使用Semaphore類同步三個線程(名爲「1」,「2」和「3」)。他們必須在控制檯中打印一個字符串,其結果是:1-> 2-> 3。這裏是我的代碼:與信號燈同步

class MyThread 
{ 
    public Thread Thrd; 
    static Semaphore sem = new Semaphore(1, 1); 
    static int flag = 1; 

    public MyThread(string name) 
    { 
     Thrd = new Thread(this.Run); 
     Thrd.Name = name; 
     Thrd.Start(); 
    } 

    void Run() 
    { 
     sem.WaitOne(); 
     if (Convert.ToInt32(Thrd.Name) == flag) 
     { 
      Console.WriteLine("Thread " + Thrd.Name); 
      flag++; 
     } 
     if (flag == 4) 
      flag = 1; 
     Thread.Sleep(300); 
     sem.Release(); 
    } 
} 

class SemaphoreDemo 
{ 
    static void Main() 
    { 
     for (int i = 0; i < 10; i++) 
     { 
      MyThread mt1 = new MyThread("1"); 
      MyThread mt2 = new MyThread("2"); 
      MyThread mt3 = new MyThread("3"); 

      mt1.Thrd.Join(); 
      mt2.Thrd.Join(); 
      mt3.Thrd.Join(); 
     } 
    } 
} 

但是有時從線程#2和#3中看不到字符串。我的錯誤在哪裏,我該如何解決這個問題?

非常感謝!

回答

2

問題是,有時線程會按順序獲取信號量,並且您沒有任何重試邏輯。看看你的Run方法。

void Run() 
{ 
    sem.WaitOne(); 
    if (Convert.ToInt32(Thrd.Name) == flag) 
    { 
     Console.WriteLine("Thread " + Thrd.Name); 
     flag++; 
    } 
    if (flag == 4) 
     flag = 1; 
    Thread.Sleep(300); 
    sem.Release(); 
} 

現在,如果名爲「3」的線程首先獲取信號量,會發生什麼? flag等於1,所以條件碼不會被執行。該線程只會休眠300毫秒,然後退出。如果你想這個工作,你必須使線程重試:

void Run() 
{ 
    bool success = false; 
    while (!success) 
    { 
     sem.WaitOne(); 
     if (Convert.ToInt32(Thrd.Name) == flag) 
     { 
      Console.WriteLine("Thread " + Thrd.Name); 
      flag++; 
      success = true; 
     } 
     sem.Release(); 
     if (!success) 
     { 
      // let somebody else try 
      Thread.Sleep(300); 
     } 
    } 
} 

這將使您的示例按預期工作。

我懷疑這只是一個練習,看看線程和信號量如何工作。但是,請注意,互斥量通常比信號量更合適,最大計數爲1.

還要注意,還有其他方法可以使線程順序執行,但如果要按順序執行線程那麼你可能不需要多於一個線程。除非那些線程正在做其他事情,他們只需要進行一次排序 - 或者很少。

+0

Jim Mischel,非常感謝! – user3649515