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

Смежные вопросы