Verständnisfrage zu pthread_cond_timedwait()

Antworten
Nachricht
Autor
_CHRIS_

Verständnisfrage zu pthread_cond_timedwait()

#1 Beitrag von _CHRIS_ » 10. Jun 2008 17:08

Hallo zusammen.

Mir ist bei Verwendung der Funktion pthread_cond_timedwait() noch etwas unklar und was ich bisher hier gesehen habe bin ich zuversichtlich, dass mir hier geholfen werden kann.

Mein Code in einem Thread sieht in etwa so aus:

Code: Alles auswählen

pthread_mutex_lock( &mutex );
pthread_cond_timedwait( &cond, &mutex, &abstime );
/*
Code ...
*/
pthread_mutex_unlock( &mutex );
Dieser Thread läuft unter der Scheduling-Policy SCHED_FIFO (Priorität 1), alle anderen unter SCHED_OTHER. Mir ist wichtig, dass dieser Thread so gut wie möglich im Sekundentakt aufgerufen wird, was ich über die Struktur abstime mache. Die condition variable spielt keine Rolle, sie wird von keinem keinem anderen thread freigegeben.

Der Thread wird also immer dann aktiviert, wenn die entsprechende Zeit zu abstime erreicht ist. Soweit so gut. Nun zu meiner Frage:

Was passiert, wenn genau zu dieser Zeit der Mutex von einem anderen Thread blockiert wird? Dann muss doch mein höher priorisierter Thread solange warten bis der Mutex wieder freigegeben wurde, womit sich ein gewisser Jitter auf meinem Sekundentakt ergibt.

Ist das richtig? Oder habe ich da noch etwas übersehen?

Benutzeravatar
Janka
Beiträge: 3585
Registriert: 11. Feb 2006 19:10

#2 Beitrag von Janka » 11. Jun 2008 12:53

Genau so ist es. Die Priorität spielt nur eine Rolle, wenn mehr als ein Thread im System im Zustand "runable" ist. Threads/Prozesse, die auf irgendeine Bedingung blockieren, sind da völlig außen vor.

Will man diesen Jitter verhindern, muss man auf das blockierende Warten auf den Mutex im höher priorisierten Thread verzichten und ihn stattdessen beim Zurückkehren aus der Wartezeit nicht blockierend abfragen (erlaubt, weil kein anderer Thread mit Kenntnis des Mutexes diesen Thread unterbrechen kann), und dann die Aktionen durchführen, die trotz der Sperre noch möglich sind.

Man kann auch komplett ohne Mutexes arbeiten, wenn man darauf achtet, dass die Aktionen, die die einzelnen Threads zur Datenübergabe durchführen, in sich atomar sind. Dann gibt es auch keinen zusätzlichen Jitter. Im allgemeinen Fall wird es aber reichen, die kritischen Abschnitte einfach so kurz wie möglich zu halten. Ein bisschen Jitter gibt es immer, weil auch die Prozessumschaltung nicht zwangsläufig immer gleich schnell abläuft und Interrupts auf Kernelebene ja noch höher priorisiert sind als jeder Prozess.

Auch an mlock() denken!

Was genau soll das denn werden?
Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

_CHRIS_

#3 Beitrag von _CHRIS_ » 17. Jun 2008 8:48

Vielen Dank für deine Antwort. War für mich in erster Linie wichtig, zu wissen dass ich das richtig verstanden habe.
Janka hat geschrieben:Will man diesen Jitter verhindern, muss man auf das blockierende Warten auf den Mutex im höher priorisierten Thread verzichten und ihn stattdessen beim Zurückkehren aus der Wartezeit nicht blockierend abfragen (erlaubt, weil kein anderer Thread mit Kenntnis des Mutexes diesen Thread unterbrechen kann), und dann die Aktionen durchführen, die trotz der Sperre noch möglich sind.
Was meinst du damit genau? Was bedeuted "nicht blockierend abfragen"? Heißt das, dass ich die Anweisung

Code: Alles auswählen

pthread_cond_timedwait( &cond, &mutex, &abstime );
ohne vorheriges

Code: Alles auswählen

pthread_mutex_lock( &mutex );
ausführen soll?
Janka hat geschrieben:Was genau soll das denn werden?
Es geht um ein Embedded Linux System, in dem mehrere Threads auf die I2C-Bus-Schnittstelle zugreifen sollen, auch der höher priorisierte. Darum brauche in den Mutex.

Benutzeravatar
Janka
Beiträge: 3585
Registriert: 11. Feb 2006 19:10

#4 Beitrag von Janka » 17. Jun 2008 21:24

_CHRIS_ hat geschrieben: Was meinst du damit genau? Was bedeuted "nicht blockierend abfragen"? Heißt das, dass ich die Anweisung

Code: Alles auswählen

pthread_cond_timedwait( &cond, &mutex, &abstime );
ohne vorheriges

Code: Alles auswählen

pthread_mutex_lock( &mutex );
ausführen soll?
Nein. Es gibt dafür pthread_mutex_trylock(). Wenn das fehlschlägt, kann der am höchsten priorisierte Thread ja trotzdem weiterarbeiten. Er darf halt nur nicht auf die gesperrte Ressource zugreifen.
_CHRIS_ hat geschrieben: Es geht um ein Embedded Linux System, in dem mehrere Threads auf die I2C-Bus-Schnittstelle zugreifen sollen, auch der höher priorisierte. Darum brauche in den Mutex.
Geschieht das Locking auf Datenpaketebene oder auf Transaktionsebene (mehrere Slaves synchron schalten)? Wenn Transaktionen unterbrochen werden dürfen, könnte man da auch noch einiges verbessern und den Jitter für den höchst priorisierten Thread so verringern.

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

_CHRIS_

#5 Beitrag von _CHRIS_ » 19. Jun 2008 15:45

Janka hat geschrieben:Nein. Es gibt dafür pthread_mutex_trylock(). Wenn das fehlschlägt, kann der am höchsten priorisierte Thread ja trotzdem weiterarbeiten. Er darf halt nur nicht auf die gesperrte Ressource zugreifen.
Danke!
Janka hat geschrieben:Geschieht das Locking auf Datenpaketebene oder auf Transaktionsebene (mehrere Slaves synchron schalten)? Wenn Transaktionen unterbrochen werden dürfen, könnte man da auch noch einiges verbessern und den Jitter für den höchst priorisierten Thread so verringern.
Da steck ich noch nicht so tief drin. Den exakten Ablauf der Kommunikation regelt ja der I2C-Treiber für mich. Was ich bis jetzt mache ist folgendes:
Zuerst öffne ich den Bus:

Code: Alles auswählen

i2c_fd = open("/dev/i2c-1", O_RDWR);
der Filedeskriptor i2c_fd ist global deklariert.
Jedes mal wenn ich mit einem Slave kommunizieren will ruf ich zuerst ioctl() auf:

Code: Alles auswählen

ioctl(i2c_fd, I2C_SLAVE, slaveaddress);
und greife dann mit read() und write() auf den Bus zu.

Den Mutex benutze ich, damit ich sicher gehen kann, dass nicht z.B. das falsche Byte an den falschen Slave geschickt wird. Wenn der Treiber das selbst regelt, wenn ich z.B. jedem Slave einen eigenen Filedeskriptor zuweise, kann ich natürlich auf den Mutex verzichten.
Leider weiß ich nicht, wie der Treiber genau funktioniert. Wo finde ich denn dazu eine Dokumentation?

Benutzeravatar
Janka
Beiträge: 3585
Registriert: 11. Feb 2006 19:10

#6 Beitrag von Janka » 19. Jun 2008 18:07

_CHRIS_ hat geschrieben: Zuerst öffne ich den Bus:

Code: Alles auswählen

i2c_fd = open("/dev/i2c-1", O_RDWR);
der Filedeskriptor i2c_fd ist global deklariert.
Jedes mal wenn ich mit einem Slave kommunizieren will ruf ich zuerst ioctl() auf:

Code: Alles auswählen

ioctl(i2c_fd, I2C_SLAVE, slaveaddress);
und greife dann mit read() und write() auf den Bus zu.

Den Mutex benutze ich, damit ich sicher gehen kann, dass nicht z.B. das falsche Byte an den falschen Slave geschickt wird.
Das ist WIMRE unnötig, denn der Treiber selbst verschickt bereits ganze Nachrichten, sortiert also die Daten aus den Filedeskriptoren selbst und kümmert sich auch um das Timing.
Leider weiß ich nicht, wie der Treiber genau funktioniert. Wo finde ich denn dazu eine Dokumentation?
Use the Source, Luke! /usr/src/linux/drivers/i2c/...

Janka
Ich vertonne Spam immer in /dev/dsp statt /dev/null.
Ich mag die Schreie.

Antworten