2009-12-02 4 views
5

Мы видим странное поведение в системах RedHat Enterprise Linux с помощью pthreads sem_timedwait. Это происходит только с версиями 5.3.sem_timedwait не поддерживается должным образом на RedHat Enterprise Linux 5.3 и далее?

Когда мы создаем семафор в фоновом потоке с sem_init, никакая ошибка не возвращается. Когда мы делаем sem_timedwait, мы получаем немедленный возврат с errno = 38 (ENOSYS), указывающий, что он не поддерживается.

Если мы делаем то же самое в основном потоке, оно работает так, как ожидалось, и мы не получаем ошибки от sem_timedwait.

Мы не видим его на RHEL 5.2 или раньше. Мы попытались скомпилировать наш код с gcc 3.2.3 и 4.1.2 и получить тот же результат, поэтому, похоже, это проблема времени выполнения.

Итак, мои вопросы (наконец);

1) Кто-нибудь еще видел это? 2) это известная проблема с RHEL 5.3? 3) мы используем sem_timedwait, чтобы спать один поток. Какие альтернативы существуют в Linux, чтобы сделать то же самое?

Если это дубликат другого вопроса, дайте мне знать. Я посмотрел, но не могу найти один с тем же вопросом, похожий на OSX, который не является тем, что мы используем.

спасибо, pxb

Update: только что сделал еще несколько испытаний со следующими результатами:

  • если сделать 64 битную сборку с помощью GCC 4.1.2 на поле RHEL5.4 (с -L/usr/lib64 и -lstdC++ -lrt) и запустить его на 64-битной установке RHEL5, он отлично работает
  • если я делаю 32-битную сборку с использованием gcc 4.1.2 в поле RHEL5.1 (с -L/usr/lib и -lstdC++ -lrt) и запустить его в точно таком же 64-битном поле RHEL5, мы получаем ошибки ENOSYS от sem_timedwait

Таким образом, для RHEL5.4 (и, по-видимому, RHEL5.3) это различие между 64 и 32-битными исполняемыми библиотеками. Единственное другое отличие заключалось в том, что 32 и 64-битные сборки были сделаны для RHEL5.1 и RHEL5.4 соответственно.

+0

Удалось исправить это, но я не знаю, как работает исправление. Код, вызывающий функции семафора, был в классе внутри .so, и они, в свою очередь, вызывались из самого исполняемого файла. Если мы переместим код из файла cpp в заголовок (т. Е. Эффективно введем класс в исполняемый файл), проблема исчезнет. так, похоже, это: на RHEL5.4, если мы вызываем sem_timedwait из .so, он терпит неудачу, но если мы делаем тот же самый вызов из исполняемого файла, он работает. И я понятия не имею, почему ... – pxb

ответ

6

Наконец-то выяснилось, в чем проблема. В RHEL 5.4, если мы будем называть sem_init, а затем sem_timedwait, мы получим несколько случайное поведение времени ожидания, в зависимости от того, где находится код, независимо от того, принадлежит ли объект sem_t к куче или стеку и т. Д. Иногда время ожидания возвращается немедленно с errno = 38 (ENOSYS), иногда он корректно ждет, прежде чем вернуться.

Запуск его через Valgrind дает эту ошибку:

==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) 

Если я бегу точно такой же код на RHEL 5.2 проблема не уходит, и Valgrind сообщения без ошибок.

Если я делаю MemSet на sem_t переменного перед вызовом sem_init проблема уходит на RHEL 5,4

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

Итак, это выглядит как ошибка была введена с семафорами на RHEL5.4 или что-то, что это использует внутренне, а sem_init неправильно инициализирует память sem_t. Или, sem_timed wait изменился, чтобы быть чувствительным к этому так, как раньше.

Интересно, что ни в коем случае sem_init не возвращает ошибку, чтобы указать, что она не работает.

В качестве альтернативы, если ожидаемое поведение является то, что sem_init не intialise памяти sem_t и это до абонента, то поведение, конечно, изменилось с RHEL 5.4

pxb

Update - вот в случае, если кто-то еще захочет попробовать его. Обратите внимание, что проблема возникает только в том случае, когда sem_timedwait вызывается из .so, и только RHEL5.4 (может быть, 5.3 не тестировал ее), и только тогда, когда он был построен как 32-битный двоичный файл (привязка к 32-разрядным библиотекам, конечно)

1) в 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) в main.cpp (обратите внимание на повторяющиеся функции тестирования, поэтому мы можем сравнить работает внутри .so с в ехе)

#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) вот 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 

Тестовые являются:

  1. бежать внутри .so, не делая MemSet
  2. бежать изнутри .so и сделать MemSet
  3. бежать изнутри ехе, не делая MemSet
  4. бежать из в ехе и не MemSet

и вот результат работает на 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 

Вы можете видеть, что случай 1 возвращается немедленно егто = 38.

Если мы запустим тот же самый код на RHEL5.2 мы получаем следующее:

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 

Вы можете видеть, что все дела теперь работают так, как ожидалось!

+0

+1 спасибо за последующее наблюдение – pmg

+0

Спасибо, тоже помог. Но я был на Ubuntu 9.10. Код работал раньше, только небольшое изменение нарушило его (началось сбой с errno 38). И memset решила проблему. – inazaruk

2

Кажется, что semtest[email protected]_2.1 звонит, и libsemtest.so звонит [email protected]_2.0.

sem_timedwait(), похоже, требует версии 2.1.

Я получил правильные результаты для всех четырех тестов, добавив -lpthread к правилу, которое создает libsemtest.so.

Я тестировал это на RH 5.3.

+1

Это на самом деле правильный подход (принятый ответ - нет). –

+0

Почему и как происходит такое несоответствие? Является ли привязка каждой библиотеки к lpthread единственным способом обеспечения их соответствия? – KyleL

 Смежные вопросы

  • Нет связанных вопросов^_^