Hallo, ich habe folgendes Problem: Durch verschiedene Programmkonstellationen kann es vorkommen, dass zwei Threads gleichzeitig gestartet werden, die jeweils eine Funktion mit verschiedenen Parametern aufrufen. (Thread A ruft Fuktion mit Parameter 1 auf und Thread B startet die Funktion mit Parameter 2) Das ganze geht manchmal so schnell, dass die Funktion nochmal aufgerufen wird, während sie noch läuft. Rausgefunden habe ich das so: Globale Variable c=0, in erster Funktionszeile c++; und am ende c--; Wenn dann nicht c==0 kommt, muss die Funktion nochmal aufgerufen worden sein, bevor sie beendet wurde. Wie kann ich das verhindern? Der Funktionsaufruf müsste in einer Warteschleife warten, bis der erste Durchlauf beendet wurde.
Hi Mutex. Wie das im Detail aussieht hängt von deinem OS bzw. deiner Treadbibliothek ab. POSIX -> pthread_mutex_* Matthias
ich würde die Funktion einfach als Atomar definieren. D.h. solange wie diese Funktion läuft, kann sie nicht durch einen anderen Thread der zu dem Prozess gehört unterbrochen werden. Ansonsten nur eine Bastellösung wie du mit dem c vorgeschlagen hast- vorsicht, da muss der Zugriff auf das c aber auch atomar ablaufen!
meister lämpchen schrieb: > ich habe folgendes Problem: Durch verschiedene Programmkonstellationen > kann es vorkommen, dass zwei Threads gleichzeitig gestartet werden, die > jeweils eine Funktion mit verschiedenen Parametern aufrufen. (Thread A > ruft Fuktion mit Parameter 1 auf und Thread B startet die Funktion mit > Parameter 2) die Frage ist erstmal wo das Problem dabei ist. Es wenn die funktion keine globalen resourcen nutzt dann ist es auch kein Problem das die funtion mehrfach gleichzeitg läuft. Also erstmal die Frage: Warum hast du ein Problem damit das du funktion nicht mehrfach laufen darf?
Peter II schrieb: > die Frage ist erstmal wo das Problem dabei ist. Es wenn die funktion > keine globalen resourcen nutzt dann ist es auch kein Problem das die > funtion mehrfach gleichzeitg läuft. Sowas nennt sich dann reentrant (http://de.wikipedia.org/wiki/Eintrittsinvarianz). Ansonsten, Mutex wurde ja schon genannt. Weitere Stichwörten wären z.B. semaphore, critical section, lock, ...
Aber wie baue ich irgendetwas vom genannten in mein C-Programm ein? Das Problem ist folgendes: Ich steuere ein IO-Interface an (über CAN-Bus). Wenn beide Threads A und B gleichzeitug gestartet werden, wird die Funktion "Lampe 1 einschalten" und "Lampe 2 einschalten" gleichzeitig ausgeführt. Und in der Schalt-Funktion kommt dann (manchmal) etwas durcheinander. Um Lampe 1 zu schalten, muss das aktuelle Ausgangsbyte mit dem Bit, das der Lampe 1 entspricht verknüpft und ausgegeben werden. Wenn gleichzeitig die Lampe 2 in der Schaltfunktion wütet, wird das Bit mit einer falschen Grundmaske maskiert. Ich möchte also zum testen, dass der Thread die Funktion so lange nicht startet, bis die eine durchgelaufen ist.
Du brauchst eine eine "Critical Section". Weitere hilfreiche Google-Suchbegriffe wären "Mutex" und "Semaphore".
meister lämpchen schrieb: > Ich möchte also zum testen, dass der Thread die Funktion so lange nicht > startet, bis die eine durchgelaufen ist. das starten der funktion ist kein problem. du musst dann nur warten. Bei windows könnte man es so machen. handle lock = createcriticalsection; void send() { EnterCriticalSection( &lock ); Sende(); LeaveCriticalSection( &lock ); } wenn jetzt 2 Thread gleicheztig die funktion aufrufen, dann wartet der 2.Thread bei EnterCriticalSection bis der 1.thread LeaveCriticalSection ausgeführt hat.
Wenn mehrere Threads gemeinsame eine Resource nutzen, wie etwas ein CAN Interface, und dieses Interface nicht selbst dafür sorgt, dass es mehrfache Verwendung serialisiert, dann muss du das tun. Und dafür sind die bereits genannten Verfahren vorgesehen. Ist ein Standardverfahren bei nebenläufiger Programmierung. Grundlagenwissen. Willst du das nun schlicht und einfach nutzen, oder willst du ein solches Verfahren implementieren? Nutzen: verrate mal, worin/worauf du programmierst. Jedes Betriebssystem bietet dir APIs dafür an. Implementieren: oops, da gehts etwas arg in die Tiefe, bis runter auf Aspekte von Rechnerarchitekturen, wenn tatsächlich PCs gemeint sind. Auf C Ebene kommst da nicht weiter, da die verwendeten Maschinenbefehle entscheidend sind. Tipp: hier gehts erstmal nicht weiter, Sackgasse, denn so wie du dir das vorstellst geht es eben nicht.
A. K. schrieb: > Implementieren: oops, da gehts etwas arg in die Tiefe, bis runter auf > Aspekte von Rechnerarchitekturen, wenn tatsächlich PCs gemeint sind. Auf > C Ebene kommst da nicht weiter, da die verwendeten Maschinenbefehle > entscheidend sind. Tipp: hier gehts erstmal nicht weiter, Sackgasse. Bei M$ käme man da schon weiter. Läßt sich über die Interlocked... Funktionen implementieren. Beispiele dafür kann man z.B. in der pthreads-win32 Lib sehen. Was die MS-API sonst so zum Theme Synchronisation zu bieten hat findet man u.a. hier: http://msdn.microsoft.com/de-de/library/ms686360.aspx
... schrieb: > Bei M$ käme man da schon weiter. Läßt sich über die Interlocked... > Funktionen implementieren. Ist aber letztlich auch nur einer jener APIs, von denen ich sprach. Nur etwas weiter unten als Mutexe. Warum das Rad neu erfinden? Hier geht es um Mutexe, und die gibts ja schliesslich auch fertig.
A. K. schrieb: > Ist ein Standardverfahren bei nebenläufiger Programmierung. > Grundlagenwissen. > > Willst du das nun schlicht und einfach nutzen, oder willst du ein > solches Verfahren implementieren? Ich möchte es eigentlich nur nutzen, sofern es (relativ einfach) möglich ist. Ich programmiere in C unter Windows 7 mit einer relativ unbekannten Entwicklungsumgebung von National Instruments. Bei HANDLE lock = CreateCriticalSection(); kommt der Fehler "missing prototype". Wo ist CreateCriticalSection definiert? Wo bekomme ich den Header dafür her?
meister lämpchen schrieb: > Wo bekomme ich den Header dafür her? Indem du die Doku von MS für diese Funktion spickst. Da steht üblicherweise drin, welcher Header zuständig ist.
... schrieb: > Bei M$ käme man da schon weiter. Läßt sich über die Interlocked... > Funktionen implementieren. Wobei da dann die Frage im Raum stünde, ob die Funktion wirklich so kurz und knapp ist, dass man sie mit Mutex-Verfahren mit aktivem Warten bedienen sollte. Denn darauf läufts damit ja raus. Wenn da Millisekunden mit Däumchendrehen draufgehen geht es anders effizienter. Überdies sollte man auch hier etwas über Architektur wissen, um sich nicht selber massiv auf den Füssen zu stehen. Denn wenn eine solche Variable in der gleichen Cache-Line landet wie eine vom so geschützten Code häufiger genutze normale Variable, dann drückt das mächtig auf die Performance. Über derartige Effekte (gibt noch mehr) sind schon manche bös gestolpert.
A. K. schrieb: > Wobei da dann die Frage im Raum stünde, ob die Funktion wirklich so kurz > und knapp ist, dass man sie mit Mutex-Verfahren mit aktivem Warten > bedienen sollte. Denn darauf läufts damit ja raus. Wenn da Millisekunden > mit Däumchendrehen draufgehen geht es anders effizienter. CriticalSection soll effentiver als Mutexe sein, aus dem grund habe ich das vorgeschlagen. meister lämpchen schrieb: > CreateCriticalSection definiert? Wo bekomme ich den > Header dafür her? kann doch nicht so schwer sein, du solltest dir eh die doku durchlesen bevor man funktionen das 1.Mal verwendet. http://msdn.microsoft.com/en-us/library/ms683472(v=vs.85).aspx sorry heist auch InitializeCriticalSection
Peter II schrieb: > CriticalSection soll effentiver als Mutexe sein, aus dem grund habe ich > das vorgeschlagen. Ist letztlich auch eine Mutex im allgemeinen Sinn. Ein anderer Name für das gleiche Grundprinzip, anders implementiert. Aus schon erwähnten Gründen gibt es heute oft mehrere Wege nach Rom, d.h. verschiedene APIs für das gleiche Prinzip, mit unterschiedlichen Nebeneffekten. Für Laufzeiten im Submikrosekundenbereich wie atomaren Variablenoperationen sind klassische OS-Mutexe völliger Irrsinn, im Millisekundenbereich ist andererseits aktives Warten Blödsinn.
A. K. schrieb: > Anderer Name für das gleiche Grundprinzip, anders implementiert. nein, dann genau das was du geschrieben hast kann man damit machen: http://msdn.microsoft.com/en-us/library/ms683476(v=VS.85).aspx
Peter II schrieb: > nein, dann genau das was du geschrieben hast kann man damit machen: Klar. Aber das ist kein Widerspruch. Für mich ist der Begriff "Mutex" ein allgemeiner Begriff bei Betriebssystemen, kein bestimmter mehr oder weniger zufällig so heissender API von Microsoft. Demzufolge ist für mich diese Critical Section ebenfalls eine Mutex, nur mit anderem Namen. Entstanden aus der erwähnten Problematik heraus, als mit SMT und Multicores die klassischen OS-Mutexe ineffizient wurden.
A. K. schrieb: > Ist letztlich auch eine Mutex im allgemeinen Sinn. Ein anderer Name für > das gleiche Grundprinzip, anders implementiert. nachtrag: eine CriticalSection gibt es nur in einem Prozess sie muss also nicht im Kernel implementiert sein. Ein Mutex kann Prozessübergreifend eingesetzt werden damit muss immer der Kernel belästig werden.
Peter II schrieb: > eine CriticalSection gibt es nur in einem Prozess sie muss also nicht im > Kernel implementiert sein. Ein Mutex kann Prozessübergreifend eingesetzt > werden damit muss immer der Kernel belästig werden. Yep, aber du reitest hier Microsofts Namenskonvention aus. Die ist für mich nicht massgeblich. Sind für mich einfach nur verschiedene Sorten Mutexe, mit unterschiedlichen Eigenheiten. Ich erlaube mir da eine etwas abgehobenere Betrachtungsweise.
Vlt. kann man das Problem auch mit einem anderen Programmierstil entschärfen. Dein Beispiel mit dem auszugebenden Byte würde ich so lösen: - im Speicher für jedes der Bits einen eigenen Puffer halten - eine Funktion schreiben, die die einzelnen Bits unabhängig voneinander setzen kann - nach jeder Änderung an einem der Bitpuffer (oder zyklisch) diese Bits zu einem Byte "zusammenkehren" und in das Ausgaberegister kopieren So dürfte es eigentlich nicht zu "Kuddelmudel" kommen ...
Frank Esselbach schrieb: > So dürfte es eigentlich nicht zu "Kuddelmudel" kommen ... Kommt drauf an, was du darunter verstehst. Es können dann nämlich Zustände auf den Ausgängen auftauchen, die in dieser Kombination zu keinem einzigen Zeitpunkt im Programm aufgetreten sind. Es sei denn du schützt das Zusammenkehren der Bits durch eine Mutex. ;-)
A. K. schrieb: > sind. Es sei denn du > schützt das Zusammenkehren der Bits durch eine Mutex. ;-) aber dafür gibt es atomar funktionen wie Interlocked... Aber ich glaube dieser Ansatz ist hier ein wenig zu kompliziert. Mit einem Mutex/CriticalSection sollte sich das Problem für meister lämpchen recht gut lösen lassen.
Peter II schrieb: > it > einem Mutex/CriticalSection sollte sich das Problem für meister lämpchen > recht gut lösen lassen. Leider nicht so richtig:
1 | LPCRITICAL_SECTION lock = InitializeCriticalSection(&lock); |
2 | EnterCriticalSection( &lock ); |
wenn das am Anfang der Funktion steht, gits Fehler. lock ist nicht initialisiert.
meister lämpchen schrieb: > Leider nicht so richtig: > LPCRITICAL_SECTION lock = InitializeCriticalSection(&lock); > EnterCriticalSection( &lock ); > wenn das am Anfang der Funktion steht, gits Fehler. lock ist nicht das LPCRITICAL_SECTION lock = InitializeCriticalSection(&lock); !!!!!!!!darf auch nicht in der funktion stehen!!!!!!!!!! scheinbar hast du noch nicht mal verstanden wie das ganze funktionieren soll. Bitte erst doku lesen. Das ist grundlagenwissen wenn man multithreaded programmiert.
meister lämpchen schrieb: > Leider nicht so richtig: > LPCRITICAL_SECTION lock = InitializeCriticalSection(&lock); > EnterCriticalSection( &lock ); Auweia. Ist es tatsächlich so schwer mal eine Duco zu lesen und vielleicht auch mal zwei, drei Links weiter zu klicken? So misarabel ist MSDN doch nu wirklich nicht. http://msdn.microsoft.com/de-de/library/ms686908.aspx
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.