2016-03-05 113 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