2012-03-28 8 views
6

Ok..ce sera long mais je dois d'abord expliquer quelques notions de base.Multithreading et ports série

Cette partie de mon logiciel est destinée à trier des articles qui descendent d'une bande transporteuse. J'utilise Modbus pour la bande transporteuse. Modbus ouvrira les portes à une heure précise pour laisser passer un objet à travers la porte. Les articles passeront par certaines portes en fonction du poids.

Je surveille un capteur pour déterminer quand un article est sur une balance. Lorsque le capteur est bloqué, l'article est pesé et envoyé à la porte appropriée. Les minuteries sont réglées pour ouvrir/fermer la porte.

Mon code fonctionnera pour ceci..le problème est, il ne fonctionnera pas pour plusieurs articles. Je veux dire par là qu'une porte est ouverte, le détecteur n'est pas surveillé tant que la porte n'est pas fermée. Donc, pendant que l'article A est sur le chemin de la porte, l'article B ne sera pas pesé sur l'échelle quand il bloque le capteur. Je pourrais avoir jusqu'à 8 articles sur la ligne à la fois. Voici le code que je suis maintenant en cours d'exécution:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
} 

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if sensor is blocked 
    if (sensorstatus == 0) 
    { 
     //the timers just start the thread 
     scaleTimer.Start(); 
    } 
    else 
    { 
     sensorTimer.Start(); 
    } 
} 

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     ReadScale(); 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     SetOpenDelay(); 
     SetDuration(); 
    } 
    } 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    //if gate = 0, this means the weight of meat on scale 
    //is not in any weight range. Meat runs off the end. 
    if (gate == 0) 
    { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
     sensorTimer.Start(); 
    } 
    else 
    { 
     //open gate 
     //then close gate 
    } 
    } 

Ce code fonctionne très bien, je dois juste être en mesure de rendre compte de plusieurs éléments sur la ligne. Des suggestions ????

J'ai aussi essayé les éléments suivants:

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (SensorThread.CancellationPending == true) 
     e.Cancel = true; 
    else 
    { 
     ReadSensor(); 
    }  
}  

private void SensorThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    sensorTimer.Start(); 
} 

    private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    if (ScaleThread.CancellationPending == true) 
    { 
     e.Cancel = true; 
    } 
    else 
    { 
     //sensor blocked 
     if (sensorstatus == 0) 
     { 
      ReadScale(); 
      //SaveWeight(); 
      prevgate = gate; 
      gate = DetermineGate(); 
      SetOpenDelay(); 
      SetDuration(); 

      //if gate = 0, this means the weight of meat on scale 
      //is not in any weight range. Meat runs off the end. 
      if (gate == 0) 
      { 
      txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                       "lbs is out of range"}); 
      } 
      else 
      { 
      //open gate 
      //close gate 
      } 
    } 
} 

private void ScaleThread_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e) 
{ 
    scaleTimer.Start(); 
} 

Quand je l'ai fait, j'ai commencé les deux fils lorsque le bouton de démarrage a été pressé. Je reçois toutes sortes d'exceptions et le programme finit par lancer SEHException et se bloque. Les autres erreurs que je reçois disent "Port série déjà ouvert" ou "Erreur E/S".

+0

Le problème est que les blocs de fil à grande échelle pendant DetermineGate(), SetOpenDelay() et SetDuration()? Je ne comprends pas encore complètement votre code. Il semble que ce soit encore très procédural même si vous utilisez des threads - il semble que les threads attendent toujours les uns des autres. Est-ce que c'est ce qui se passe? –

+0

FYI, voici un excellent lien sur le multithreading en C#: http://www.yoda.arachsys.com/csharp/threads/index.shtml –

+0

Ceci est ma première fois multithreading.J'en avais besoin là où mon interface graphique ne serait pas bloquée. Je ne suis pas sûr de ce que vous entendez par "les blocs d'échelle de fil" Les fils sont en attente les uns des autres .. mais quand j'ai essayé de le réparer, j'ai juste eu un tas d'erreurs (voir mon édition). J'ai besoin de ce logiciel pour pouvoir faire fonctionner une bande transporteuse. Il devrait tenir compte des éléments passant par le capteur à un taux de dire ... 1 article toutes les 3 secondes. Donc, toutes les portes doivent s'ouvrir/se fermer lorsque l'objet arrive à sa porte. Je sais que cela semble déroutant ... comprenez-vous ce que j'essaie d'accomplir? Merci pour le lien – CSharpDev

Répondre

1

Je suggère que votre meilleur pari est probablement de créer un fil dédié à s'asseoir sur chaque port série. Une telle approche n'exigera ni n'interdira aucune similitude dans la façon dont les ports sont traités, évitera toute interférence dans le fonctionnement entre les ports, et sera évolutive dans des limites raisonnables (l'utilisation d'un thread pour chacun des 32 ports serait bien; un fil pour chacun de 1000 serait mauvais). Bien qu'il faille éviter de créer des threads qui s'exécuteront brièvement et s'arrêteront, ou créer un très grand nombre de threads, l'utilisation d'un thread dédié pour chaque port série garantira que le thread sera prêt à gérer les données.

+0

J'ai essayé cela. J'avais un fil dédié au capteur et un dédié à l'échelle. Le fil d'échelle n'a saisi le poids que si le capteur était bloqué (quelque chose était sur la balance). Puis, une fois que j'avais le poids, je produisais un fil pour manipuler les portes. Je ne ferais jamais cela à ce fil parce que j'ai eu des erreurs avec la lecture de la balance et du capteur. Ces deux threads ne fonctionneraient pas ensemble. Ils sont sur différents ports COM et tout, donc je ne suis pas sûr quoi de neuf – CSharpDev

+0

Ma suggestion aurait été de lancer tous les threads au démarrage et les laisser simplement en cours d'exécution. Le démarrage des threads est coûteux. Laisser inutilement un thread exécuter du code inutilement coûte très cher. Laisser un thread s'asseoir bloqué en attente d'E/S, cependant, est comparativement beaucoup moins cher. Pas si bon marché que l'on devrait avoir des centaines courir sans raison, mais assez bon marché que huit serait généralement pas un gros problème. – supercat

1

Je remarque que vous n'avez aucune boucle dans les méthodes DoWork de votre thread. Ce serait un bon endroit pour commencer. Le thread de travail doit être une boucle qui ne retourne pas jusqu'à ce que CancellationPending soit défini sur true. Ils ne se boucleront pas d'eux-mêmes parce que vous les avez dans un thread - le thread s'exécutera jusqu'à ce que ce soit fait, puis quittera.

Édité pour ajouter: Ce que vous semblez manquer, c'est que vous devez diviser le code qui surveille l'échelle et le code qui ouvre et ferme la porte. Une façon de le faire serait d'avoir une boucle infinie qui surveille l'échelle, et quand il détecte quelque chose, il commence un nouveau thread qui gère l'ouverture et la fermeture de la porte.

+0

Merci Charlie (et Tom) pour l'upvote. D'après ce que j'ai compris, je pense que la boucle est "causée" par un fil appelant l'autre. – AlexDev

+0

Gotcha, mais l'OP utilise toujours du code procédural - une méthode ne s'exécutera pas tant que l'autre méthode ne l'aura pas appelée. L'idée dans le threading est d'avoir un code qui s'exécute indépendamment d'un autre, et quand il trouve quelque chose qui est long (comme ouvrir et fermer les portes), il engendre ce travail dans un nouveau thread. Ou est-ce que je manque quelque chose? –

+0

Je boucle le thread dans la méthode RunWorkerCompleted. Il démarre une minuterie qui appelle le fil après qu'il se soit déclenché. – CSharpDev

2

Je pense que vous avez besoin de quelque chose comme ça. Je ne sais pas si les verrous sont nécessaires, mais je les ai ajouté pour la sécurité puisque vous obtenez des erreurs

private void SensorThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    int sensor = 1; 
    while(!SensorThread.CancellationPending == true) 
    { 
     int newSensor; 
     lock(this) 
     { 
      newSensor = ReadSensor(); 
     } 

     //sensor state changed 
     if(newSensor != sensor) 
     { 
      //sensor was 1 and changed to 0 
      if(newSensor==0) 
      { 
       scaleTimer.Start(); 
      } 
      sensor = newSensor; 
     } 
     Thread.Sleep(1); 
    } 
    e.Cancel = true; 
}  

private void ScaleThread_DoWork(object sender, DoWorkEventArgs e) 
{ 
    //sensor blocked 
    //if (sensorstatus == 0) 
    { 
     lock(this) 
     { 
      ReadScale(); 
     } 
     //SaveWeight(); 
     prevgate = gate; 
     gate = DetermineGate(); 
     lock(this) 
     { 
      SetOpenDelay(); 
      SetDuration(); 
     } 

     //if gate = 0, this means the weight of meat on scale 
     //is not in any weight range. Meat runs off the end. 
     if (gate == 0) 
     { 
     txtStatus.Invoke(new UpdateStatusCallback(UpdateStatus), new object[] { meatweight.ToString() + 
                      "lbs is out of range"}); 
     } 
     else 
     { 
     lock(this) 
     { 
     //open gate 
     } 
     lock(this) 
     { 
     //close gate 
     } 
     } 
    } 
+0

alors le newSensor devrait-il commencer comme une vraie valeur? pouvez-vous élaborer un peu sur ce que vous faites ici? – CSharpDev

+0

Correction de l'initialisation newSensor. L'idée, comme d'autres l'ont suggéré, est que le fil du capteur boucle en vérifiant le capteur et lorsqu'il détecte un changement d'état, il déclenche le fil d'échelle. – AlexDev

+0

Je vais essayer et voir ce qui se passe. Merci! – CSharpDev

Questions connexes