Constamment la lecture à partir d'un port série avec un thread d'arrière-plan

Que le port de communication série asynchrone, j'ai compris tôt dans mon projet impliquant la communication avec une interface RS 232 de l'appareil que je vais avoir un thread d'arrière-plan constamment la lecture du port pour les données reçues. Maintenant, je suis en utilisant IronPython (.NET 4.0) et j'ai donc accès à la nappe de classe SerialPort construit dans .NET. Cela me permet d'écrire du code comme ceci:

self.port = System.IO.Ports.SerialPort('COM1', 9600, System.IO.Ports.Parity.None, 8, System.IO.Ports.StopBits.One)
self.port.Open()
reading = self.port.ReadExisting() #grabs all bytes currently sitting in the input buffer

Assez Simple. Mais comme je l'ai mentionné, je veux être constamment vérifier ce port pour les nouvelles données qu'il arrive. Idéalement, j'aurais l'OS dire - moi à tout moment il y a de données en attente. Whaddaya savez, mes prières ont été exaucées, il y a un DataReceived événement!

self.port.DataReceived += self.OnDataReceived

def OnDataReceived(self, sender, event):
    reading = self.port.ReadExisting()
    ...

Dommage que ce soit inutile, bien que, parce que cet événement n'est pas garanti d'être soulevé!

La DataReceived événement n'est pas garanti d'être soulevées pour chaque octet reçu.

Donc, retour à l'écriture d'un thread d'écoute, puis. J'ai accompli ce assez rapidement avec un BackgroundWorker qui appelle simplement port.ReadExisting() encore et encore. Il lit les octets comme ils viennent, et quand il voit une fin de ligne (\r\n), il place ce qu'elle a lu dans un linebuffer. Puis d'autres parties de mon programme d'oeil à la linebuffer pour voir s'il y a des lignes complètes en attente d'être utilisés.

Maintenant, c'est un classique producteur-consommateur le problème, évidemment. Le producteur est le BackgroundWorker, de placer des lignes complètes en linebuffer. Le consommateur est un code qui consomme ces lignes à partir de la linebuffer aussi vite que possible.

Toutefois, le consommateur est en quelque sorte inefficace. Actuellement, il est constamment vérifier la linebuffer, obtenir déçu à chaque fois de trouver vide; mais chaque fois dans un certain temps de trouver une ligne d'attente à l'intérieur. Quelle est la meilleure façon d'optimiser, ce afin que le consommateur ne se réveille quand il y a une ligne disponibles? De cette façon, le consommateur n'est pas à la faire tourner en permanence accès à la linebuffer, ce qui peut entraîner certains problèmes de concurrence.

Aussi, si il est plus simple/la meilleure façon de lire en permanence à partir d'un port série, je suis ouvert aux suggestions!

OriginalL'auteur Aphex | 2010-11-12