Probleme mit SystemV-Semaphoren unter Linux
-
Hallo Leute. Dieser Post wird leider ein wenig länger.
Ich schreibe (für eine Hochschul-Arbeit) eine Klasse, die Puffer verwaltet. Dabei gibt es eine Liste für volle Puffer und eine für leere Puffer.
In meiner Anwendung erzeuge ich beliebig viele Prozesse (64, 128, ...), die sich leere Puffer zum Schreiben oder volle Puffer zum Auslesen holen.Um den Spaß zu synchronisieren benutze ich SystemV Semaphoren. Und zwar pro Liste (leere Puffer, volle Puffer) einen Semaphor für den gegenseitigen Ausschluss (damit immer nur 1(!) Prozess auf einer Liste Veränderungen vornehmen kann). Dazu verwende ich pro Liste noch einen zählenden Semaphor, damit ein Prozess erst aktiviert wird, wenn Puffer in der Liste vorhanden sind.
Hier die wichtigsten Methoden der Klasse, in der ich diese Operationen realisiere:
void bufferpool::initSems(int param_semCount) { // create the semaphors semFull = semget(IPC_PRIVATE, 1, IPC_CREAT|0777); semEmpty = semget(IPC_PRIVATE, 1, IPC_CREAT|0777); semFullCount = semget(IPC_PRIVATE, 1, IPC_CREAT|0777); semEmptyCount = semget(IPC_PRIVATE, 1, IPC_CREAT|0777); // configure the semaphors semctl(semFull, 0, SETALL); semctl(semEmpty, 0, SETALL); semctl(semFullCount, 0, SETALL); semctl(semEmptyCount, 0, SETALL); // prepare to set the counting semaphors values to @param_semCount this->initCount.sem_num = 0; this->initCount.sem_op = param_semCount; this->initCount.sem_flg = SEM_UNDO; // for locking a semaphor, we have to add -1 to the semaphor this->lock.sem_num = 0; this->lock.sem_op = -1; this->lock.sem_flg = SEM_UNDO; // for unlocking a semaphor, we have to add 1 to the semaphor this->unlock.sem_num = 0; this->unlock.sem_op = 1; this->unlock.sem_flg = SEM_UNDO; // unlock the "binary" semaphors for first time use semop(semFull, &unlock, 1); semop(semEmpty, &unlock, 1); // set counting semaphor to @param_semCount, because there are // @param_semCount empty buffers to use semop(semEmptyCount, &initCount, 1); } void bufferpool::addFullBuffer() { semop(semFull, &lock, 1); // add a full buffer to list of full buffers semop(semFullCount, &unlock, 1); semop(semFull, &unlock, 1); } void bufferpool::addEmptyBuffer() { semop(semEmpty, &lock, 1); // add an empty buffer to list of empty buffers semop(semEmptyCount, &unlock, 1); semop(semEmpty, &unlock, 1); } void bufferpool::releaseFullBuffer() { semop(semFullCount, &lock, 1); semop(semFull, &lock, 1); // release a full buffer from list of full buffers semop(semFull, &unlock, 1); } void bufferpool::releaseEmptyBuffer() { semop(semEmptyCount, &lock, 1); semop(semEmpty, &lock, 1); // release an empty buffer from list of empty buffers semop(semEmpty, &unlock, 1); }
In meiner Anwendung erzeuge ich dann eine Instanz der Klasse und verschiedene Prozesse, die damit arbeiten sollen.
Die Anwendung:
bufferpool *myPool; void reader() { myPool->releaseFullBuffer(); // Puffer leeren myPool->addEmptyBuffer(); } void writer() { myPool->releaseEmptyBuffer(); // Puffer füllen myPool->addFullBuffer(); } void create_reader_writer() { /* create n childs * * n/2 childs -> reader() * n/2 childs -> writer() */ } int main() { myPool = new bufferpool(); create_reader_writer(); return 0; }
Nun tritt folgendes Phänomen auf. Die ganze Sache läuft mehrere Minuten (!) ohne jegliche Probleme. Aber dann verweigern die zählenden Semaphoren (semFullCount, semEmptyCount) ihren Dienst und die Prozesse greifen auf die Methoden zu, obwohl es keine Puffer gibt, und sie eigentlich warten sollten. Die debug-Ausgaben zeigen mir dann, dass die zählenden Semaphoren unmögliche Werte enthalten (323675, 1265, 76903, ...), obwohl ich sie nur mit 128 initialisiert habe.
Kann mir irgendjemand sagen, was hier falsch läuft? Habe ich die Initialisierungen falsch vorgenommen? Ich sitze jetzt seit mehreren Wochen an diesem Phänomen und weiß keinen Rat mehr, deswegen frage ich hier.
Vielen Dank im Voraus.
PS: Sorry für diesen Monster-Post...