2009-12-26 74 views
1

經過我的任務調度程序的某個階段的測試後,我幾乎隨機地遇到了一個死鎖。我想問一些幫助,特別是我想知道我的方法是否會陷入僵局,或者如果問題在別處。
開始之前我會說應用程序是一個全屏遊戲。 (以防它可能會影響任何東西)
我會用文字解釋系統是如何工作的。死鎖,一些問題

任務調度

1)的附表2每個CPU的任務在每一個幀的開始。 (通過調度我的意思是設置任務的私人WaitHandle設置允許任務做一些工作)

下面是一個簡短的代碼,總結系統正在做的兩個任務中的每一個。

   Scheduled++; 
       InternalLock.Reset(); 

在完成這兩項任務之後,他們通過設置Private WaitHandle開始。

2)等待所有任務完成。等待是通過等待內部WaitHandle來完成的,每個任務都必須發送信號。 (WaitOne的()上的每個任務)

這裏是等待的代碼:

if (Attese.Length > 0) 
    { 
     TmpIsSucceded = false; 
     for (int i = 0; i < Attese.Length; i++) 
     { 
      WaitHandle actual = Attese[i].Wait; 
      do 
      { 
       TmpIsSucceded = actual.WaitOne(150); 
       if (!TmpIsSucceded) 
        EnginesManager.ProcessMessages(); 
      } while (!TmpIsSucceded); 
     } 
    } 

任務

1)永遠不會關閉,直到比賽結束。
2)有2個內部WaitHandle。一位私人人員在他爲他工作時講述任務。當任務結束其工作時,一個內部信號發出。 (任務調度程序正在等待的那個)
3)當任務完成時,自己啓動任務調度程序的synchronized(by lock())隊列中可用的另一個任務(同樣通過設置私有waithandle該任務)。

這是任務的主循環:

 private void CoreThread() 
     { 
      while (_active) 
      { 
       PrivateLock.WaitOne(-1, false); 
       while (Scheduled > 0) 
       { 
        if (OnThreadExecute != null) 
         OnThreadExecute(this, null); 
        Scheduled--; 
        if (Scheduled == 0) 
        { 
         PrivateLock.Reset(); 
         if (OnThreadEnd != null) 
          OnThreadEnd(this, null); 
         InternalLock.Set(); 
        } 
       } 
      } 
     } 

InternalLock和PrivateLock是兩個waitHandles。請注意,InternalLock等待句柄僅在此代碼中設置。沒有其他地方設置InternalLock或PrivateLock。 (我發佈的代碼除外)

當發生死鎖時,任務調度程序正在等待所有要完成的任務,但其中一個任務從未設置InternalLock等待句柄。 「已阻止」任務在「PrivateLock.WaitOne(-1,false)」停止;當發生死鎖時。

任何人都有關於這種僵局的線索?

編輯:

internal void StartSchedule() 
    { 
     for (int i = 0; i < Tasks.Length; i++) 
     { 
      if (Tasks[i].Schedule()) 
       QTasks.Enqueue(Tasks[i]); 
     } 
     StartThreadAvailable(); 
    } 

    private void StartThreadAvailable() 
    { 
     TempExecList.Clear(); 
     for (int i = 0; i < NThread; i++) 
     { 
      if (QTasks.Count > 0) 
       TempExecList.Add(QTasks.Dequeue()); 
     } 
     Int32 count = TempExecList.Count; 
     for (int i = 0; i < count; i++) 
      TempExecList[i].StartThread(); 
    } 

    internal void StartThread() 
    { 
     PrivateLock.Set(); 
    } 

這裏的地方專用手柄的設置()的要求被調用的代碼。

Schedule()在這種情況下總是返回true。(只加1的任務調度變量和重置InternalLock)

編輯2:

這裏的2類爲問代碼:

http://pastebin.com/m225f839e(GameTask)

http://pastebin.com/m389629cd(TaskScheduler)

+0

請出示包含'PrivateLock的代碼。Set()' –

+0

添加了代碼 – feal87

+0

您是如何聲明等待句柄的?你能發佈一個完整的編譯樣本嗎? –

回答

0

我發現了這個問題。這是一個非常愚蠢的一個...

我會解釋所以別人有這個問題可以利用的遊離缺失我的時間。 XD 無論如何,非常感謝John Knoeller,通過它的洞察力幫助我縮小了問題的範圍。 :d

讓我們來看看主線程。 InternalLock.Set()在任務調度程序線程中設置該塊並說「繼續」。比方說,在任務調度的任務只是1.和想象這種狀況是否

1)第一步

任務調度程序 - 調度
TASK 1 - 等待

2)第二步

任務調度器 - WAITING
TASK 1 - WORK

3)第三步驟

任務調度器 - WAITING
TASK 1 - InternalLock.Set();

4)第四步

任務調度器 - SCHEDULE
TASK 1 - |而(預定> 0)|

在第四步驟導致SCHEDULE在主線程遞增預定的變量。這種方式一直沒有結束,導致代碼中的所有干擾(和死鎖)。我通過在InternalLock.Set()之後簡單地添加一個break來修復這個問題。 現在沒有問題。

(對於那些說我正在訪問狀態而沒有同步的人請注意,在任何線程都被賦予工作之前,Schedule函數只被調用一次,所以無論它是否同步都沒關係該問題是一個非常愚蠢的一個我的壞:。d)

謝謝!

1

沒有顯示Scheduled的實現,但是在我看來,這個變量的增量和減量之間可能存在競爭。我想你可能需要在這裏使用InterlockedDecrement,而且我也覺得更舒服,如果有測試之間的計劃> 0和測試計劃== 0

更多類似這樣的

PrivateLock.WaitOne(-1, false); 
while (true) 
{ 
    // fetch Sched, so the whole loop sees a single value 
    int iSched = Scheduled--; // implementation should be Interlocked.Decrement() 
    if (iSched <= 0) 
    { 
     if (iSched < 0) 
     { 
      // should never get here, throw exception? 
     } 
     PrivateLock.Reset();     
     if (OnThreadEnd != null)     
      OnThreadEnd(this, null);     
     InternalLock.Set();     
     break; // break out of while 
    } 

    if (OnThreadExecute != null)    
     OnThreadExecute(this, null); 
} 
無房
+0

我增加了整個代碼,並在此期間,我會嘗試你的建議。 – feal87