Verständnisfrage zu pthread_cond_timedwait()

Post Reply
Message
Author
_CHRIS_

Verständnisfrage zu pthread_cond_timedwait()

#1 Post by _CHRIS_ »

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: Select all

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?

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#2 Post by Janka »

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 Post by _CHRIS_ »

Vielen Dank für deine Antwort. War für mich in erster Linie wichtig, zu wissen dass ich das richtig verstanden habe.
Janka wrote: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: Select all

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

Code: Select all

pthread_mutex_lock( &mutex );
ausführen soll?
Janka wrote: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.

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#4 Post by Janka »

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

Code: Select all

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

Code: Select all

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_ wrote: 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 Post by _CHRIS_ »

Janka wrote: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 wrote: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: Select all

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: Select all

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?

User avatar
Janka
Posts: 3585
Joined: 11. Feb 2006 19:10

#6 Post by Janka »

_CHRIS_ wrote: Zuerst öffne ich den Bus:

Code: Select all

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: Select all

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.

Post Reply