2009-12-02 15 views
5

Wir sehen seltsames Verhalten auf RedHat Enterprise Linux-Systemen mit pthreads sem_timedwait. Es tritt erst ab Version 5.3 auf.sem_timedwait wird auf RedHat Enterprise Linux 5.3 nicht richtig unterstützt?

Wenn wir den Semaphor in einem Hintergrundthread mit sem_init erstellen, wird kein Fehler zurückgegeben. Wenn wir sem_timedwait ausführen, erhalten wir eine sofortige Rückkehr mit errno = 38 (ENOSYS), was anzeigt, dass es nicht unterstützt wird.

Wenn wir das gleiche auf dem Hauptthread tun, funktioniert es wie erwartet und wir erhalten keinen Fehler von sem_timedwait.

Wir sehen es nicht auf RHEL 5.2 oder vorher. Wir haben versucht, unseren Code mit gcc 3.2.3 und 4.1.2 zu kompilieren und das gleiche Ergebnis zu erhalten, es scheint also ein Laufzeitproblem zu sein.

Also, meine Fragen (endlich;)

1) hat jemand gesehen? 2) Ist es ein bekanntes Problem mit RHEL 5.3? 3) wir verwenden sem_timedwait um einen einzelnen Thread zu schlafen. Welche Alternativen gibt es unter Linux, um das Gleiche zu tun?

Wenn dies ein Duplikat einer anderen Frage ist, lassen Sie es mich wissen. Ich habe gesucht, kann aber keinen mit der gleichen Frage finden, nur ähnliche für OSX, was wir nicht verwenden.

Dank, PXB

Update: nur einige Tests mit den folgenden Ergebnissen durchgeführt:

  • wenn ich ein 64-Bit-Build gcc 4.1.2 auf einer RHEL5.4 Box mit (mit -L/usr/lib64 und -lstdC++ -lrt) und es auf einer 64-Bit-Installation von RHEL5 läuft es funktioniert gut
  • wenn ich eine 32-Bit-Build mit gcc 4.1.2 auf einer RHEL5.1-Box (mit -L/usr/lib und -lstdC++ -lrt) und es auf einer exakt gleichen 64-Bit-RHEL5-Box ausführen, erhalten wir ENOSYS-Fehler von sem_timedwait

Es scheint also ein Unterschied zwischen den 64 und 32-Bit-Laufzeitbibliotheken auf RHEL5.4 (und scheinbar RHEL5.3) zu sein. Der einzige andere Unterschied bestand darin, dass die 32- und 64-Bit-Builds jeweils aus RHEL5.1- und RHEL5.4-Boxen bestanden.

+0

Managed, um es zu beheben, aber ich bin mir nicht sicher, wie der Fix funktioniert. Der Code, der die Semaphorfunktionen aufruft, befand sich in einer Klasse innerhalb eines .so, und diese wurden wiederum von der ausführbaren Datei selbst aufgerufen. Wenn wir den Code aus der cpp-Datei in den Header verschieben (dh die Klasse effektiv in die ausführbare Datei einfügen), verschwindet das Problem. so scheint es zu sein: auf RHEL5.4 wenn wir die sem_timedwait von innerhalb der .so es schlägt fehl, aber wenn wir den gleichen Aufruf von der ausführbaren Datei es funktioniert. Und ich habe keine Ahnung, warum ... – pxb

Antwort

6

Schließlich herausgefunden, was das Problem ist. Auf RHEL 5.4, wenn wir sem_init aufrufen, dann sem_timedwait, erhalten wir ein zufälliges Verhalten des zeitgesteuerten Wartens, abhängig davon, wo sich der Code befindet, ob das Objekt, das sem_t besitzt, auf dem Heap oder Stack ist. Manchmal kehrt die zeitgesteuerte Wartezeit sofort zurück mit errno = 38 (ENOSYS), manchmal wartet es richtig, bevor es zurückkehrt.

es über valgrind Lauf gibt diesen Fehler:

==32459== Thread 2: 
==32459== Syscall param futex(op) contains uninitialised byte(s) 
==32459== at 0x406C78: sem_timedwait (in /lib/libpthread-2.5.so) 
==32459== by 0x8049F2E: TestThread::Run() (in /home/stsadm/semaphore_test/semaphore_test) 
==32459== by 0x44B2307: nxThread::_ThreadProc(void*) (in /home/stsadm/semaphore_test/libcore.so) 
==32459== by 0x4005AA: start_thread (in /lib/libpthread-2.5.so) 
==32459== by 0x355CFD: clone (in /lib/libc-2.5.so) 

Wenn ich genau den gleichen Code ausführen auf RHEL 5.2 das Problem verschwindet und valgrind Berichte keine Fehler.

Wenn ich ein memset auf der sem_t Variable vor sem_init Aufruf des Problems auf RHEL weggeht 5,4

memset(&_semaphore, 0, sizeof(sem_t)); 

Also, es sieht aus wie ein Bug mit Semaphore auf RHEL5.4 oder etwas eingeführt wurde, dass es verwendet intern, und sem_init initialisiert den sem_t-Speicher nicht korrekt. Oder das sem_timed-Warten hat sich verändert, um auf eine Weise sensibel zu sein, wie es vorher nicht war.

Interessanterweise gibt sem_init in keinem Fall einen Fehler zurück, um anzuzeigen, dass es nicht funktioniert hat.

Alternativ kann, wenn das erwartete Verhalten ist, dass sem_init nicht die Erinnerung an sem_t intialise wird, und das ist bis zu dem Anrufer, dann hat sich das Verhalten sicherlich mit RHEL 5.4

geändert

PXB

Update - hier ist der Test-Case-Code, falls jemand anderes es versuchen möchte. Beachten Sie, dass das Problem nur auftritt, wenn sem_timedwait von einem .so aufgerufen wird, und nur RHEL5.4 (vielleicht 5.3 hat es nicht getestet) und nur als 32-Bit-Binärcode (gegen 32-Bit-Bibliotheken natürlich)

1) in semtest.cpp

#include <semaphore.h> 
#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <time.h> 

void semtest(int semnum, bool initmem) 
{ 
     sem_t sem; 

     if (initmem) 
     { 
       memset(&sem, 0, sizeof(sem_t)); 
       printf("sem %d: memset size = %d\n", semnum, sizeof(sem_t)); 
     } 

     errno = 0; 
     int res = sem_init(&sem, 0, 0); 

     printf("sem %d: sem_init res = %d, errno = %d\n", semnum, res, errno); 

     timespec ts; 
     clock_gettime(CLOCK_REALTIME, &ts); 
     ts.tv_sec += 1; 

     errno = 0; 
     res = sem_timedwait(&sem, &ts); 

     printf("sem %d: sem_timedwait res = %d, errno = %d\n\n", semnum, res, errno); 
} 

2) in main.cpp (man beachte die doppelte Testfunktion so können wir aus dem .so mit der exe)

#include <semaphore.h> 
#include <stdio.h> 
#include <string.h> 
#include <errno.h> 
#include <time.h> 

extern void semtest(int semnum, bool initmem); 

void semtest_in_exe(int semnum, bool initmem) 
{ 
     sem_t sem; 

     if (initmem) 
     { 
       memset(&sem, 0, sizeof(sem_t)); 
       printf("sem %d: memset size = %d\n", semnum, sizeof(sem_t)); 
     } 

     errno = 0; 
     int res = sem_init(&sem, 0, 0); 

     printf("sem %d: sem_init res = %d, errno = %d\n", semnum, res, errno); 

     timespec ts; 
     clock_gettime(CLOCK_REALTIME, &ts); 
     ts.tv_sec += 1; 

     errno = 0; 
     res = sem_timedwait(&sem, &ts); 

     printf("sem %d: sem_timedwait res = %d, errno = %d\n\n", semnum, res, errno); 
} 

int main(int argc, char* argv[], char** envp) 
{ 
     semtest(1, false); 
     semtest(2, true); 
     semtest_in_exe(3, false); 
     semtest_in_exe(4, true); 
} 

3 laufen vergleichen) hier ist das Makefile

all: main 

semtest.o: semtest.cpp 
     gcc -c -fpic -m32 -I /usr/include/c++/4.1.2 -I /usr/include/c++/4.1.2/i386-redhat-linux semtest.cpp -o semtest.o 

libsemtest.so: semtest.o 
     gcc -shared -m32 -fpic -lstdc++ -lrt semtest.o -o libsemtest.so 

main: libsemtest.so 
     gcc -m32 -L . -lsemtest main.cpp -o semtest 

Die Testfälle sind:

  1. Lauf aus .so ohne Memset ohne dabei Memset
  2. laufen
  3. Lauf aus .so und tun Memset
  4. Lauf aus exe zu tun aus innerhalb exe und do

memset und hier läuft das Ergebnis auf RHEL5.4

sem 1: sem_init res = 0, errno = 0 
sem 1: sem_timedwait res = -1, errno = 38 

sem 2: memset size = 16 
sem 2: sem_init res = 0, errno = 0 
sem 2: sem_timedwait res = -1, errno = 110 

sem 3: sem_init res = 0, errno = 0 
sem 3: sem_timedwait res = -1, errno = 110 

sem 4: memset size = 16 
sem 4: sem_init res = 0, errno = 0 
sem 4: sem_timedwait res = -1, errno = 110 

Sie können diesen Fall 1 kehrt sofort mit errno siehe = 38.

Wenn wir den exakt gleichen Code auf RHEL5.2 laufen bekommen wir folgendes:

sem 1: sem_init res = 0, errno = 0 
sem 1: sem_timedwait res = -1, errno = 110 

sem 2: memset size = 16 
sem 2: sem_init res = 0, errno = 0 
sem 2: sem_timedwait res = -1, errno = 110 

sem 3: sem_init res = 0, errno = 0 
sem 3: sem_timedwait res = -1, errno = 110 

sem 4: memset size = 16 
sem 4: sem_init res = 0, errno = 0 
sem 4: sem_timedwait res = -1, errno = 110 

können Sie sehen, dass Alle Fälle funktionieren jetzt wie erwartet!

+0

+1 Dank für das Follow-up – pmg

+0

Danke, hat mir auch geholfen. Aber ich war auf Ubuntu 9.10. Code funktionierte vorher, nur ein kleiner Wechsel brachte es kaputt (begann mit Fehlern 38 zu versagen). Und memset hat das Problem gelöst. – inazaruk

2

Es scheint, dass semtest ruft [email protected]_2.1, und libsemtest.so ruft [email protected]_2.0.

sem_timedwait() scheint Version 2.1 zu erfordern.

Ich habe korrekte Ergebnisse für alle vier Tests erhalten, indem ich -lpthread zu der Regel hinzufügt, die libsemtest.so erstellt.

Ich habe dies auf RH 5.3 getestet.

+1

Dies ist eigentlich der richtige Ansatz (die akzeptierte Antwort ist nicht). –

+0

Warum und wie tritt diese Art von Diskrepanz auf? Ist die Verknüpfung jeder Bibliothek gegen Lpthread der einzige Weg, um sicherzustellen, dass sie konsistent sind? – KyleL

Verwandte Themen