2009-12-26 3 views
1

После некоторого этапа тестирования моего планировщика задач я столкнулся с тупиком довольно случайным образом. Я хочу попросить некоторую помощь, особенно я хочу знать, может ли мой подход зайти в тупик или проблема в другом месте.
Прежде чем начать, я скажу, что приложение представляет собой полноэкранную игру. (в случае, если это может повлиять на что-либо)
Я объясню словами, как работает система.Тупик, некоторые вопросы

Задача планировщика

1) Расписание 2 на CPU задач в начале каждого кадра. (по планированию я имею в виду установку частного WaitHandle задачи для установки, позволяющую задаче выполнить некоторую работу)

Вот короткий код, который суммирует, что система делает с каждой из двух задач.

   Scheduled++; 
       InternalLock.Reset(); 

После того, как все две задачи запланированы, они начинаются с установки частного 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) Когда задача сама по себе запускает другую задачу, доступную в синхронизированной (по блокировке()) очереди планировщика задач (таким же образом, устанавливая приватную 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. Обратите внимание на то, что функция waistandle InternalLock установлена ​​только в этом коде. НЕТ ДРУГОГО МЕСТА, где установлены InternalLock или PrivateLock. (за исключением кода, который я опубликовал)

Когда возникает тупик, планировщик задач ждет выполнения всех задач, но одна из задач никогда не устанавливает waithandle InternalLock. «Заблокированная» задача останавливается на «PrivateLock.WaitOne (-1, false)»; когда происходит тупик.

Кто-нибудь подскажет об этом тупике?

Edit:

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(); 
    } 

вот код, где Set() Частного ручки называется спросил.

Schedule() return всегда истинно в этом случае.(Это только добавить 1 к запланированной переменной задачи и сброса InternalLock)

EDIT 2:

Вот код из 2-х классов, спросил:

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

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

+0

Пожалуйста, покажите код, который содержит 'PrivateLock.Set() ' –

+0

Добавил код, заданный – feal87

+0

, как вы объявили дескрипторы ожидания? можете ли вы опубликовать полный компиляционный образец? –

ответ

0

Я выяснил, проблема. Это было действительно глупо ...

Я объясню, что любой другой, имеющий эту проблему, может использовать время, которое я потерял. XD В любом случае очень спасибо Джону Кноллеру, который помог мне сузить проблему с ее проницательностью. : D

Давайте рассмотрим главную тему. InternalLock.Set() устанавливает блок в потоке планировщика задач и говорит «идти вперед». Допустим, что задача в планировщик задач являются только 1. И представьте себе эту возможную ситуацию

1) Первый шаг

ЗАДАЧА SCHEDULER - ГРАФИК
ЗАДАЧА 1 - WAIT

2) Второй этап

ЗАДАЧИ ПЛАНИРОВЩИК - ОЖИДАНИЕ
Задачи 1 - РАБОТА

3) Третий шаг

ЗАГРУЗКА ЗАГРУЗКИ - ОЖИДАНИЕ
TASK 1 - InternalLock.Set();

4) Четвертый этап

ЗАДАЧА SCHEDULER - ГРАФИК
ЗАДАЧА 1 - | в то время (по расписанию> 0) |

На четвертом шаге причина, по которой SCHEDULE в основном потоке увеличивала запланированную переменную. Таким образом, время не прекратило все нарушения в коде (и в тупике). Я исправил, просто добавив разрыв после InternalLock.Set(); Теперь нет проблем.

(для людей, которые сказали, что я обращаюсь к состоянию без синхронизации. Обратите внимание, что функция 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

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