2009-12-26 9 views
1

Après une phase de test de mon planificateur de tâches, j'ai rencontré une impasse à peu près aléatoire. Je veux demander de l'aide, surtout je veux savoir si mon approche peut aboutir à une impasse ou si le problème est ailleurs.
Avant de commencer, je dirai que l'application est un jeu en plein écran. (au cas où cela pourrait influencer quelque chose)
Je vais expliquer en mots comment le système fonctionne.Impasse, quelques questions

Le Planificateur de tâches

1) L'annexe 2 par tâches CPU au début de chaque trame. (en programmant je veux dire en réglant le WaitHandle privé de la tâche à définir permettant à la tâche de faire un peu de travail)

Voici un court code qui résume ce que le système fait avec chacune des deux tâches. Une fois que toutes les deux tâches sont planifiées, elles sont initialisées en définissant le WaitHandle privé.

2) Attendez que toutes les tâches soient terminées. L'attente est effectuée en attendant que le WaitHandle interne indique que chaque tâche doit être signalée. (WaitOne() sur chaque tâche)

Voici le code de l'attente:

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

La tâche

1) est jamais fermé jusqu'à la fin du jeu.
2) A 2 WaitHandle interne. Un privé qui raconte la tâche quand il y a du travail pour lui. Un interne qui est signalé lorsque la tâche a terminé son travail. (celui attendu par le planificateur de tâches)
3) Lorsque la tâche est terminée, lancez elle-même une autre tâche disponible dans une file d'attente synchronisée (par lock()) du planificateur de tâches (de la même manière en définissant le waithandle privé de cette tâche).

c'est la boucle principale de la tâche:

 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 et PrivateLock sont les deux waitHandles. Veuillez noter que le waithandle InternalLock est uniquement défini dans ce code. Il n'y a AUCUN AUTRE ENDROIT où InternalLock ou PrivateLock sont installés. (sauf pour le code que j'ai posté)

Lorsque le blocage se produit, le planificateur de tâches attend que toutes les tâches soient terminées, mais l'une des tâches ne définit jamais le waithandle InternalLock. La tâche "bloquée" est arrêtée au "PrivateLock.WaitOne (-1, false);" ligne quand l'impasse se produit.

Quelqu'un at-il une idée de cette impasse?

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

est ici le code où l'ensemble() de la poignée privée est appelée comme demandé. Schedule() renvoie toujours vrai dans ce cas.

(Il ajouter seulement 1 à la variable prévue de la tâche et remettre le InternalLock)

EDIT 2:

Voici le code des 2 classes comme demandé:

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

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

+0

Veuillez montrer le code qui contient 'PrivateLock.Set() ' –

+0

Ajout du code demandé – feal87

+0

Comment avez-vous déclaré les handles d'attente? pouvez-vous poster un échantillon de compilation complet? –

Répondre

0

J'ai découvert le problème. C'était vraiment stupide ...

Je vais vous expliquer si quelqu'un d'autre ayant ce problème peut utiliser le temps perdu. XD En tout cas, merci beaucoup à John Knoeller qui m'a aidé à affiner le problème avec sa perspicacité. : D

Jetons un coup d'œil au fil principal. InternalLock.Set() définit le bloc sur le thread du planificateur de tâches et dit «allez-y». Disons que la tâche dans le planificateur de tâches ne sont que 1. Et imaginez cette situation POSSIBLE

1) Première étape

TÂCHE ORDONNANCEUR - ANNEXE
Tâche 1 - ATTENDRE

2) Deuxième étape

planificateur de tâches - ATTENTE
Tâche 1 - TRAVAIL

3) Troisième étape

PROGRAMMATEUR DE TÂCHES - EN ATTENTE
TÂCHE 1 - InternalLock.Set();

4) Quatrième étape

PLANNING DE TRAVAIL - ANNEXE
Tâche 1 - | while (Programmé> 0) | A la quatrième étape, la variable SCHEDULE du thread principal a incrémenté la variable programmée à la quatrième étape. De cette façon, le temps ne s'est pas terminé causant toutes les perturbations dans le code (et l'impasse). J'ai corrigé en ajoutant simplement une pause après le InternalLock.Set(); Maintenant, il n'y a pas de problème.

(aux personnes qui ont dit que j'accédais à l'état sans synchronisation.) Veuillez noter que la fonction Schedule n'est appelée qu'une seule fois avant même que TOUS les threads aient du travail, donc peu importe si elle est synchronisée ou non. Le problème était vraiment stupide, mon mauvais.: D)

Merci !!!

1

La mise en œuvre de Scheduled n'apparaît pas, mais il me semble que il pourrait y avoir une course entre incrémenteurs et decrementers de cette variable. Je pense que vous devrez peut-être utiliser InterlockedDecrement ici, et je serais également plus à l'aise s'il n'y avait pas de place entre le test programmé> 0 et le test == programmé 0.

plus comme celui-ci

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

J'ai ajouté le code entier, et en attendant je vais essayer votre conseil. – feal87