Laden...

SerialPort: IsOpen-Property, Problem bei mehreren Threads

Erstellt von The_Mexican vor 15 Jahren Letzter Beitrag vor 14 Jahren 3.979 Views
The_Mexican Themenstarter:in
87 Beiträge seit 2009
vor 15 Jahren
SerialPort: IsOpen-Property, Problem bei mehreren Threads

Hey,
ich habe ein problem bzgl. dem feststellen ob ein SerialPort geöffnet ist.

Sachverhalt:
ich habe zwei Klassen, Class A und Class B.

Class A:
enthält den Ablauf das ein freier Port gefunden, geöffnet und anschließend daran mit dem Port gearbeitet werden soll. (dieser Ablauf ist in einer Methode implementiert welche einem Thread zugeordnet ist).

Class B:
enthält das Wissen/ Funktionalität einen freien Port zu finden und zu öffnen.
Es gibt eine Menge x an definierten Ports mit denen gearbeitet werden soll (ist in .config angegeben und wird von dort ausgelesen).

Ablauf:
Class A:
besitzt eine Semaphore, welche verhindert, dass sich mehrere Threads bei der Wahl ihres Ports in die Quere kommen.
während sich ein Thread in der Semaphore befindet wird die Methode Find() aus Class B aufgerufen.
Class B - Find():
enthält die definierten ports aus .config und ermittelt alle verfügbaren Ports auf dem lokalen Computer - GetPortNames() (beide informationen werden in seperaten variablen gehalten). Im ersten Schritt wird in Find() überprüft ob ein in .config definierter Port auf dem lokalen Computer vorhanden ist. Im zweiten Schritt prüft Find() ob der definierte Port, welcher auf dem lokalen Computer auch vorhanden ist bereits geöffnet ist - IsOpen-Property. Ist der Port noch nicht geöffnet wird der Port initialisiert (Parity, BaudRate, ....).
Class A wird über den erfolg oder nicht erfolg des Vorgangs informiert. Im Falle des Erfolgs, veranlasst Class A im nächsten Schritt mit dem Initialisierten Object von Class B das öffnen des Ports. (Methode in Class B, welche SerialPort.Open() )
Ist auch das öffnen des Ports erfolgreich wird die Semaphore verlassen (das geschieht übrigens auch im Fehlerfall, dass die Semaphore frei wird). Der nächste Thread sucht sich seine Serielle Schnittstelle - wiederholung des beschriebenen Ablaufs.

Problem:
wurde ein Port durch den ersten Thread geöffnet wird er dem zweiten Thread WIEDER als verfügbar und noch nicht geöffnet angezeigt. das wiederum führt dann beim versuch diesen Port zu öffnen ( Class B - SerialPort.Open(); ) erst zu einer Exception.

Frage:
welche Möglichkeit(en) habe ich außer "IsOpen" festzustellen das ein SerialPort bereits geöffnet ist???

mfg
the_mexican

que? como? no entiendo!!!!!

72 Beiträge seit 2008
vor 15 Jahren

welche Möglichkeit(en) habe ich außer "IsOpen" festzustellen das ein SerialPort bereits geöffnet ist???

Eigentlich keine - denn genau dafür ist die Property ja da. Uu. bekommst Du das Öffnen noch mit, wenn Du auf das PinChanged Event reagierst. Funktioniert natürlich nur, wenn ein Kabel angeschlossen ist und nicht nur die RX,TX und Ground Leitungen verwendet werden.

Die Frage sollte daher eher lauten: Warum zeigt IsOpen an, das der Port geschlossen ist obwohl er es nicht ist? Was mich ein wenig stutzig gemacht hat an deinen Ausführungen ist die Verwendung der Semaphore. Wie kannst Du den damit sicherstellen das nicht zwei Threads auf ein und denselben SerialPort zugreifen? Denn das dürfte der Grund sein warum die IsOpen Property falsch angezeigt wird. Steht der Threadcounter der Semaphore auf 1?

Bau doch einfach mal Testweise ein Sleep(5) nach dem Serialport.Open() ein - steht dann die IsOpen Property immer noch auf false?

The_Mexican Themenstarter:in
87 Beiträge seit 2009
vor 15 Jahren

sers LuckyGeorge,

danke für die antwort. die semaphore (so dachte ich zumindest) regelt dass jeweils nur ein thread eine bestimmte aktion durchführt. ist ein thread in der semaphore kann ein weiterer Thread erst dann die aktion ausführen (Find() und Open()) wenn der erste Thread diese verlassen hat. zumindest habe ich es so definiert.

das seltsame ist, (habe ich heute mittag festgestellt) befindet sich ein thread in der semaphore ist port.IsOpen auf true gesetzt. verlässt der Thread die semaphore, ist port.IsOpen "false".

PinChanged-Event sagt mir gerade nichts, aber ich werde es mir gleich morgen anschauen (leider habe ich heute keine gelegenheit mehr).

Danke für die antwort und den denkansatz. falls dir vlt. noch was einfällt, wäre ich natürlich dankbar 😉.

schönen abend noch,
greets mex

que? como? no entiendo!!!!!

The_Mexican Themenstarter:in
87 Beiträge seit 2009
vor 15 Jahren

das PinChanged-Event können wir ausschließen, habe bereits mit einem tool das Vorgänge auf com-ports protokolliert erfolgreich getestet, dass der port auch tatsächlich geöffnet wird.

Tool: HDD Free Serial Port Monitor

que? como? no entiendo!!!!!

72 Beiträge seit 2008
vor 15 Jahren

Wie bereits gesagt - ich vermute den Fehler bei der Semaphore. Diese ist ja eigentlich nicht dazu gedacht nur einem Thread Zugriff zu gewähren sondern sovielen wie im Konstruktor angegeben. Wenn also beim Konstruktor 2 Threads angegeben wurde so können auch beide gleichzeitig in die Routine reinspringen.
Wenn Du wirklich nur einem Thread Zugriff gewähren möchtest ist ein Monitor oder ein lock die bessere Alternative. Ob aber wirklich zwei Threads gleichzeitig in die Routine reinspringen kannst Du ja mittels einer Debugausgabe am Anfang der Routine feststellen.

SerialPort.Open() braucht ca. 5 ms - natürlich abhängig von der Hardware. Meine Vermutung ist - ohne deinen genauen Code zu kennen, daß innerhlab dieser 5 ms versucht wird die Serialport.Open nochmal aufzrufen.

Anbei ein kleiner Codeschnipsel:


public partial class Form1 : Form
{
private SerialPort _localSerial;
private BackgroundWorker _bgWorker1 = new BackgroundWorker();
private BackgroundWorker _bgWorker2 = new BackgroundWorker();
private Semaphore _sem;

public Form1()
{
InitializeComponent();

_localSerial = new SerialPort("COM1";);
_bgWorker1.DoWork += new DoWorkEventHandler(_bgWorker_DoWork);
_bgWorker2.DoWork += new DoWorkEventHandler(_bgWorker_DoWork);

_sem = new Semaphore(3, 3);

_bgWorker1.RunWorkerAsync();
_bgWorker2.RunWorkerAsync();

}

void _bgWorker_DoWork(object sender, DoWorkEventArgs e)
{
_sem.WaitOne();

if (!_localSerial.IsOpen)
_localSerial.Open();

_sem.Release();
}
}

Wird der Code so aufgerufen fliegt eine Exception bei SerialPort.Open() da beide Backgroundworker zeitgleich versuchen auf den Port zuzgreifen.

Ändere ich:

_sem = new Semaphore(3, 3);

zu

_sem = new Semaphore(1, 3);

fliegt die Exception nicht mehr da nur noch ein ThreadSlot für die Semaphore frei ist.

The_Mexican Themenstarter:in
87 Beiträge seit 2009
vor 14 Jahren

hey,

sry für die späte antwort, ich möchte das thema nur noch schnell zu ende bringen. Das geschilderte Problem (so vermute ich) wurde durch die selbst eingebaute Threadsicherheit erzeugt. nachdem ich alle Bereiche zur Threadsicherheit entfernt habe, lief die Anwndung ohne probleme - ich schließe daraus (ohne Gewähr) dass das Framework bereits Multithreading-fähig ist bzw. diese Dinge selbst managt.

Warum ich mir so sicher bin, dass die anwendung ohne probleme läuft - ich habe sie einem Last- und Stresstest unterzogen. dabei gab es keinerlei probleme bezüglich multithreading.

mfg
mex

que? como? no entiendo!!!!!

49.485 Beiträge seit 2005
vor 14 Jahren

Hallo The_Mexican,

ich schließe daraus (ohne Gewähr) dass das Framework bereits Multithreading-fähig ist

das Framework als ganzes ist nicht thread-sicher. Ob eine bestimmte Klasse thread-sicher ist oder nicht, steht in ihrer Beschreibung in der :rtfm: Doku. Die wenigsten Klassen sind thread-sicher.

herbivore