RedHat Enterprise Linux 5.3以上不支持sem_timedwait?

我们在RedHat Enterprise Linux系统上看到了使用pthreads sem_timedwait的奇怪行为。 只有版本5.3以上才会出现。

当我们用sem_init在后台线程上创build信号量时,不会返回任何错误。 当我们执行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

更新:刚刚做了更多的testing,结果如下:

  • 如果我在RHEL5.4盒子(使用-L / usr / lib64和-lstdc ++ -lrt)上使用gcc 4.1.2进行64位构build,并在64位安装的RHEL5上运行,
  • 如果我在RHEL5.1盒子(使用-L / usr / lib和-lstdc ++ -lrt)上使用gcc 4.1.2来构build32位版本,并在一个完全相同的64位RHEL5盒子上运行它,我们得到ENOSYS错误sem_timedwait

所以,看起来RHEL5.4(和看似RHEL5.3)上的64位和32位运行库是有区别的。 唯一的区别是32位和64位构build分别完成了RHEL5.1和RHEL5.4盒。

最后找出问题所在。 在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报告没有错误。

如果我在调用sem_init之前在sem_t变量上做了一个memset,问题就会在RHEL 5.4上消失

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

所以,看起来像是在RHEL5.4上引入了信号量的问题,或者是在内部使用的东西,而sem_init不能正确初始化sem_t内存。 或者,sem_timed的等待已经改变,以前所未有的方式对此敏感。

有趣的是,在任何情况下,sem_init都不会返回错误,表明它不起作用。

或者,如果预期的行为是sem_init不会初始化sem_t的内存,而这取决于调用者,那么行为已经随着RHEL 5.4

PXB

更新 – 这里是测试用例代码,以防其他人想要尝试它。 注意,这个问题只发生在从.so调用sem_timedwait时,只有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和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)这里是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. 从exe文件内运行,而不用做memset
  4. 从exe中运行并执行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立即以errno = 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 

你可以看到现在所有的情况都按预期工作!

看来semtest正在调用sem_init@GLIBC_2.1 ,而libsemtest.so正在调用sem_init@GLIBC_2.0

sem_timedwait()似乎需要版本2.1。

通过向创建libsemtest.so的规则添加-lpthread ,我可以得到正确的结果。

我已经在RH5.3上测试过了。