2016-03-05 93 views
2

我道歉的事實,我張貼在這裏這個長的代碼,但我沒有其他辦法來幫助你重現我的問題。我給你的代碼當然是我正在使用的縮略圖。 我知道我可以使用QueueUserWorkItem,直到最近我還在使用它,但是我意識到我的線程太短,以至於我的ThreadDispatcher方法在第一個完成之前沒有啓動第二個方法。所以我想看看這種做法是否更快。問題是我有一個僵局,我真的不明白爲什麼。 我發佈的代碼可以直接編譯和重現問題。在C自制線程池的多線程死鎖#

using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Threading; 

namespace TestWhatever 
{ 
    public class Program 
    { 
     static MyClass ThisClass = new MyClass(); 
     static void Main() 
     { 
      ThisClass.Start(); 
      for (int Cnt = 0; Cnt < 5; Cnt++) 
      { 
       Console.WriteLine("Launching Frame " + Cnt); 
       ThisClass.Update();//Frames loop 
      } 
     } 
    } 

    public class MyClass 
    { 
     Random MyRandom = new Random(); 

     public static object _MultiDispatcherLocker = new object(); 
     public static bool MonoDispacherThreadLocked = true; 
     public static bool MultiDispacherThreadLocked = true; 
     // Thread pool in multithreading case 
     private int MaxThreadsInParallel = 5; 
     private static int MaxNumOfPool = 20; 
     private Thread[] ThreadsPool; 
     public static object _ThreadLockerList; 
     private Func<string>[] ThreadFunctions; 
     public bool[] ThreadLockedBools = Enumerable.Repeat(true, MaxNumOfPool).ToArray(); 


     public void Start() 
     { 
      StartThreads(); 
     } 

     public void Update() 
     { 

      lock (_MultiDispatcherLocker) 
      { 
       MultiDispacherThreadLocked = false; 
       Monitor.Pulse(_MultiDispatcherLocker); 
      } 
      Thread.Sleep(1000); 
     } 

     private void StartThreads() 
     { 
      ThreadsPool = new Thread[MaxNumOfPool]; 
      _ThreadLockerList = new object(); 
      ThreadFunctions = new Func<string>[MaxNumOfPool]; 
      ThreadLockedBools = new bool[MaxNumOfPool]; 

      for (int Cnt = 0; Cnt < MaxNumOfPool; Cnt++) 
      { 
       Console.WriteLine("Preparing ThreadID: " + Cnt); 
       ThreadLockedBools[Cnt] = true; 
       ThreadsPool[Cnt] = new Thread(new ParameterizedThreadStart(LaunchThread)); 
       ThreadsPool[Cnt].Start(Cnt); 
      } 

      Thread ThreadedMainThread = new Thread(new ThreadStart(ThreadDispatcher)); 
      ThreadedMainThread.Start(); 
      ThreadedMainThread.Priority = System.Threading.ThreadPriority.Highest; 
     } 

     private void LaunchThread(object iThreadID) 
     { 
      int ThreadID = (int)iThreadID; 
      lock (_ThreadLockerList) 
      { 
       while (ThreadLockedBools[ThreadID]) 
        Monitor.Wait(_ThreadLockerList); 
      } 
      while (true) 
      { 
       Console.WriteLine("Starting ThreadID: " + ThreadID); 
       ThreadFunctions[ThreadID](); 
       Console.WriteLine("Ending ThreadID: " + ThreadID); 
       lock (_MultiDispatcherLocker) 
       { 
        ThreadLockedBools[ThreadID] = true; 
        MultiDispacherThreadLocked = false; 
        Monitor.Pulse(_MultiDispatcherLocker); 
       } 
       lock (_ThreadLockerList) 
       { 
        Console.WriteLine("Blocking ThreadID: " + ThreadID); 
        while (ThreadLockedBools[ThreadID]) 
         Monitor.Wait(_ThreadLockerList); 
       } 
      } 
     } 


     private void ThreadDispatcher()//object Obj) 
     { 
      lock (_MultiDispatcherLocker) 
      { 
       while (MultiDispacherThreadLocked) 
        Monitor.Wait(_MultiDispatcherLocker); 
      } 
      while (true) 
      { 

       for (int Cnt = 0; Cnt < 20; Cnt++)//Threads loop 
       { 

        if (RunningThreads() < MaxThreadsInParallel) 
        { 
         int CurrIntTest = MyRandom.Next(100000, 10000000); 

         int ThreadID = GetNextEmptyThread(); 


         ThreadFunctions[ThreadID] =() => { MyMethodInThread(CurrIntTest); return null; }; 
         lock (_ThreadLockerList) 
         { 
          ThreadLockedBools[ThreadID] = false; 
          Monitor.Pulse(_ThreadLockerList); 
         } 
        } 
        else//wait until someone ends 
        { 
         lock (_MultiDispatcherLocker) 
         { 
          while (MultiDispacherThreadLocked) 
          { 
           Monitor.Wait(_MultiDispatcherLocker); 
          } 
         } 
        } 
       } 

       lock (_MultiDispatcherLocker) 
       { 
        MultiDispacherThreadLocked = true; 
        while (MultiDispacherThreadLocked) 
         Monitor.Wait(_MultiDispatcherLocker); 
       } 
      } 
     } 

     private void MyMethodInThread(int Counter) 
     { 
      List<string> MyDummy = new List<string>(); 
      for (int Cnt = 0; Cnt < Counter; Cnt++) MyDummy.Add("Dummy"); 
     } 

     private int RunningThreads() 
     { 
      int ToReturn = 0; 
      for (int Cnt = 0; Cnt < MaxThreadsInParallel; Cnt++) 
      { 
       if (!ThreadLockedBools[Cnt] || ThreadsPool[Cnt].ThreadState != System.Threading.ThreadState.WaitSleepJoin) 
        ToReturn++; 
      } 
      return ToReturn; 
     } 

     private int GetNextEmptyThread() 
     { 
      for (int Cnt = 0; Cnt < MaxThreadsInParallel; Cnt++) 
      { 
       if (ThreadLockedBools[Cnt] && ThreadsPool[Cnt].ThreadState == System.Threading.ThreadState.WaitSleepJoin) 
        return Cnt; 
      } 
      return -1; 
     } 

    } 
} 

如果你能幫我解決這個問題,那真是太棒了。

+1

你設計了它,你修復它。對線程的顯式微管理是臭名昭着的:1)出錯,2)當它不可用時:( –

回答

1

讓我們看看你有什麼。

LaunchThread多個線程):

lock (_ThreadLockerList) 
{ 
    while (ThreadLockedBools[ThreadID]) 
     Monitor.Wait(_ThreadLockerList); 
} 

ThreadDispatcher線程):

lock (_ThreadLockerList) 
{ 
    ThreadLockedBools[ThreadID] = false; 
    Monitor.Pulse(_ThreadLockerList); 
} 

Monitor.Pulse呼叫釋放的線程可能不是一個與ThreadLockedBools[ThreadID] = false,在這種情況下它會立即再次進入Monitor.Wait,從而有效地進食t他發出信號。

要解決此問題(並且通常在這種情況下),請改用Monitor.PulseAll

+0

YEs !!這樣做,非常感謝! – Yann