PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : pthread condition variables


liquid
2014-01-12, 20:14:29
Hallo,

ich habe momentan folgendes Konstrukt bei mir:
typedef struct data {
pthread_mutex_t mutex;
unsigned i;
/* more stuff */
} data_t;

void function_a(data_t *d) {
pthread_mutex_lock(&d->mutex);

/* do stuff with d */

pthread_mutex_unlock(&d->mutex);
}


void function_b(data_t *d, unsigned i) {
pthread_mutex_lock(&d->mutex);

/* do stuff with d */

pthread_mutex_unlock(&d->mutex);
}


Es gibt zwei Threads, die function_a und function_b aufrufen. Der Mutex verhindert, dass die Threads gleichzeitig an den Daten in d rumfummeln.

Jetzt möchte ich aber folgendes haben.

Die Threads rufen function_b mit grundsätzlich monoton steigendem Index i auf. Grundsätzlich, da ein Thread manchmal schneller mit seiner Arbeit fertig ist, und somit eine Sequenz ala "..., 13, 14, 16, 15, 17, ..." entsteht.

In d befindet sich der Index, der als nächstes dran ist. Ich möchte nun, dass der Eintritt in function_b nur für denjenigen Thread möglich ist, der den richtigen Index liefert. Der andere Thread soll geblock werden, bis er "an der Reihe ist".

Ich habe mit dazu bereits die condition variables der pthread Bibliothek angesehen. Ich bin mir aber noch nicht ganz im Klaren wie ich das genau damit bewerkstelligen kann. Muss ich z.B. einen zusätzlichen Mutex einführen, oder geht das auch mit dem bisherigen.

Jemand eine Idee?

- liquid

liquid
2014-01-13, 00:14:42
Habe mir jetzt folgendes überlegt.

void function_b(data_t *d, unsigned i) {

if (i != d->i) {
pthread_mutex_lock(&d->order_mutex);
while (i != d->i) {
pthread_cond_wait(&d->order_cond, &d->order_mutex));
}
pthread_mutex_unlock(&d->order_mutex);
}

pthread_mutex_lock(&d->mutex);

/* do stuff with d */

pthread_mutex_lock(&d->order_mutex);
pthread_cond_signal(&d->order_mutex);
pthread_mutex_unlock(&d->order_mutex);

pthread_mutex_unlock(&d->mutex);

}

Brauche also noch einen order mutex and die zugehörige condition. Sagen wir mal thread 0 ist mit seiner Berechnung schneller als geplant fertiggewesen, und ruft jetzt function_b auf. Dann wartet thread 0 im obigen while-loop (while-loop wegen spurious wakeups). Währenddessen ist thread 1 mit seinem Kram fertig. Da thread 0 nicht der nächste war, muss thread 1 also der nächste sein, und wir überspringen das if. thread 1 holt sich den Mutex, und erledigt seinen Kram. Kurz bevor es den Mutex zurückgibt, signalisiert es die condition. thread 0 verlässt den Loop und trifft auf den mutex lock call. Derweil gibt thread 1 den Mutex zurück und kehrt aus function_b zurück. thread 0 holt sich den Mutex und macht seinen Kram.

Was mir noch zu denken gibt, ist das folgende: Woher weiß der Compiler, dass der while-loop abbricht, und er diesen nicht zu einer Endlosschleife optimieren kann? Geht er davon aus, dass das Objekt auf welches d zeigt, durch den Schleifenrumpf verändert werden kann?

Marscel
2014-01-13, 00:56:15
typedef struct data {
pthread_mutex_t mutex;
volatile unsigned i;
} data_t;

Das "volatile" sollte den Compiler davon abhalten, nun noch irgendwas statisch auszuwerten und zu optimieren.

Ectoplasma
2014-01-13, 00:58:08
Es wäre hilfreicher, wenn du mal erklären würdest, was du eigentlich genau damit bezwecken möchtest, bzw., was die Funktion sein soll. Irgendwie klingt dein Vorhaben nämlich nach "wie verwende ich Threads und führe dessen Vorteile ad absurdum".

liquid
2014-01-13, 04:37:20
Es wäre hilfreicher, wenn du mal erklären würdest, was du eigentlich genau damit bezwecken möchtest, bzw., was die Funktion sein soll. Irgendwie klingt dein Vorhaben nämlich nach "wie verwende ich Threads und führe dessen Vorteile ad absurdum".
drm.c (https://gitorious.org/lima-drm/lima-drm/source/e7a8c8a0fab8b3ddcc9eef7bc3b57e9c9faf9692:limare/lib/drm.c)

function_a ist drm_get_mali_phys, function_b ist drm_flip. limare spawned zwei Renderthreads, die es irgendwie auf die GPU Kerne legt. Die Interna sind mir nicht bekannt, noch will ich im limare Kerncode irgend etwas ändern.

Ich habe also das Problem, dass Frames eventuell nicht mit monoton steigendem Index in drm_flip eintreffen. Momentan, siehe den Code, werden diese Frames gedroppt. Das ist aber nicht sonderlich sauber. Deshalb nöchte ich den Eintritt in drm_flip für Frames blocken, die noch nicht an der Reihe sind.

Das hat also keineswegs etwas mit "threads ad absurdum" führen zu tun. Die beiden Renderthreads sind nunmal da. Siehe sie einfach als gegeben an. Daran kann, und will ich nichts ändern, da mir dann vermutlich der restliche limare Code um die Ohren fliegt. Das Problem muss also im Backend zu beheben sein.

Ectoplasma
2014-01-13, 09:25:20
Eigentlich sollte das klappen. Nicht ganz so sicher bin ich mir bei "if (i != d->i)". Hier hat man evtl. ein double checked (http://www.cs.umd.edu/~pugh/java/memoryModel/DoubleCheckedLocking.html) Problem. Siehe hierzu auch: Memory barrier (http://en.wikipedia.org/wiki/Memory_barrier)

liquid
2014-01-14, 01:29:21
Ich denke die if-Abfrage könnte man auch weglassen. Ich wollte nur das Holen des Mutex überspringen, wenn der Loop sowieso direkt abbricht.

Ich werde das mal testen, und gucken wie sich der Code verhält...

liquid
2014-01-14, 22:49:27
Habe die if-Abfrage jetzt drin gelassen, und das Blocken im Code jetzt genauso implementiert. Scheint zu funktionieren, lasse mir grade ein paar drehende Würfel anzeigen.