2009-12-02 26 views
5

Chúng tôi đang nhìn thấy hành vi kỳ lạ trên hệ thống RedHat Enterprise Linux với pthreads sem_timedwait. Nó chỉ xảy ra với các phiên bản 5.3 trở đi.sem_timedwait không được hỗ trợ đúng cách trên RedHat Enterprise Linux 5.3 trở đi?

Khi chúng ta tạo semaphore trên một chuỗi nền với sem_init, không có lỗi nào được trả về. Khi chúng ta thực hiện sem_timedwait, chúng ta sẽ có một sự trả về ngay lập tức với errno = 38 (ENOSYS) cho biết nó không được hỗ trợ.

Nếu chúng tôi thực hiện tương tự trên chuỗi chính, nó hoạt động như mong đợi và chúng tôi sẽ không nhận được lỗi từ sem_timedwait.

Chúng tôi không thấy nó trên RHEL 5.2 hoặc trước đây. Chúng tôi đã thử biên dịch mã của chúng tôi với gcc 3.2.3 và 4.1.2 và nhận được kết quả tương tự, do đó, nó có vẻ là một vấn đề thời gian chạy.

Vì vậy, câu hỏi của tôi (cuối cùng;)

1) có ai khác nhìn thấy điều này không? 2) có phải là vấn đề đã biết với RHEL 5.3 trở đi không? 3) chúng tôi đang sử dụng sem_timedwait để ngủ một sợi đơn. Những lựa chọn thay thế nào có trên Linux để làm điều tương tự?

Nếu đây là bản sao của một câu hỏi khác, hãy cho tôi biết. Tôi đã nhìn nhưng không thể tìm thấy một với cùng một câu hỏi, chỉ là những cái tương tự cho OSX mà không phải là những gì chúng tôi đang sử dụng.

cảm ơn, pxb

Cập nhật: chỉ cần thực hiện một số thử nghiệm nhiều hơn với kết quả như sau:

  • nếu tôi làm một xây dựng 64 bit sử dụng gcc 4.1.2 trên một hộp RHEL5.4 (với -L/usr/lib64 và -lstdC++ -lrt) và chạy nó trên một cài đặt 64 bit của RHEL5 nó hoạt động tốt
  • nếu tôi làm một bản 32 bit bằng gcc 4.1.2 trên một hộp RHEL5.1 (với -L/usr/lib và -lstdC++ -lrt) và chạy nó trên chính xác cùng một hộp RHEL5 64 bit, chúng tôi nhận được lỗi ENOSYS từ sem_timedwait

Vì vậy, nó dường như là sự khác biệt giữa lib 64 và 32 bit thời gian chạy trên RHEL5.4 (và dường như RHEL5.3). Sự khác biệt duy nhất là 32 và 64 bit xây dựng đã được thực hiện của RHEL5.1 và RHEL5.4 hộp tương ứng.

+0

Được quản lý để khắc phục sự cố, nhưng tôi không chắc chắn tại sao bản sửa lỗi hoạt động. Mã gọi các hàm semaphore nằm trong một lớp bên trong một .so, và chúng lần lượt được gọi từ chính tệp thực thi. Nếu chúng tôi di chuyển mã từ tệp cpp sang tiêu đề (ví dụ: hiệu chỉnh nội tuyến lớp vào tệp thi hành) thì sự cố sẽ biến mất. vì vậy, nó có vẻ như thế này: trên RHEL5.4 nếu chúng ta gọi sem_timedwait từ bên trong .so nó không thành công, nhưng nếu chúng ta thực hiện cùng một cuộc gọi từ tệp thực thi nó hoạt động. Và tôi không biết tại sao ... – pxb

Trả lời

6

Cuối cùng đã tìm ra vấn đề là gì. Trên RHEL 5.4 nếu chúng ta gọi sem_init thì làm sem_timedwait chúng ta nhận được hành vi ngẫu nhiên của thời gian chờ, tùy thuộc vào vị trí mã, cho dù đối tượng sở hữu sem_t là trên heap hay stack, vv Đôi khi thời gian chờ đợi trả về ngay lập tức với errno = 38 (ENOSYS), đôi khi nó chờ đợi chính xác trước khi trở về.

Chạy nó qua valgrind cho lỗi này:

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

Nếu tôi chạy chính xác cùng mã trên RHEL 5.2 vấn đề đi xa và valgrind báo cáo không có lỗi.

Nếu tôi làm một memset trên biến sem_t trước khi gọi sem_init vấn đề đi xa trên RHEL 5,4

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

Vì vậy, nó trông giống như một lỗi đã được giới thiệu với Cột trên RHEL5.4 hoặc cái gì đó nó sử dụng nội bộ và sem_init không khởi tạo chính xác bộ nhớ sem_t. Hoặc, sem_timed wait đã thay đổi để nhạy cảm với điều này theo cách trước đây.

Điều thú vị là không có trường hợp nào sem_init trả lại lỗi để cho biết lỗi đó không hoạt động.

Ngoài ra, nếu hành vi dự kiến ​​là sem_init sẽ không intialise ký ức của sem_t và đó là lên đến người gọi, sau đó hành vi đã chắc chắn thay đổi với RHEL 5.4

pxb

Update - đây là kiểm tra mã trường hợp trong trường hợp bất cứ ai khác muốn thử nó. Lưu ý vấn đề chỉ xảy ra khi sem_timedwait được gọi từ một .so, và chỉ RHEL5.4 (có thể 5.3 chưa thử nghiệm), và chỉ khi được xây dựng dưới dạng nhị phân 32 bit (liên kết với 32 bit libs của khóa học)

1) trong 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) trong main.cpp (chú ý chức năng kiểm tra trùng lặp vì vậy chúng tôi có thể so sánh chạy từ bên trong .so với trong 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) đây là 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 

Các trường hợp kiểm tra là:

  1. chạy từ bên trong mà không làm .so memset
  2. chạy từ bên trong .so và làm memset
  3. chạy từ bên trong exe mà không làm memset
  4. chạy từ bên trong exe và làm memset

Và đây là kết quả chạy trên 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 

Bạn có thể thấy trường hợp đó 1 lợi nhuận ngay lập tức với errno = 38.

Nếu chúng ta chạy các mã chính xác như nhau trên RHEL5.2 chúng tôi nhận được như sau:

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 

Bạn có thể thấy rằng tất cả các trường hợp giờ đây hoạt động như mong đợi!

+0

+1 cảm ơn vì đã theo dõi – pmg

+0

Cảm ơn, đã giúp tôi. Nhưng tôi đã ở trên Ubuntu 9.10. Mã đã được làm việc trước đây, chỉ cần một chút thay đổi đã phá vỡ nó (bắt đầu thất bại với errno 38). Và memset đã giải quyết được vấn đề. – inazaruk

2

Có vẻ như semtest đang gọi [email protected]_2.1, và libsemtest.so đang gọi [email protected]_2.0.

sem_timedwait() dường như yêu cầu phiên bản 2.1.

Tôi nhận được kết quả chính xác cho tất cả bốn thử nghiệm bằng cách thêm -lpthread vào quy tắc tạo ra libsemtest.so.

Tôi đã thử nghiệm điều này trên RH 5.3.

+1

Đây thực sự là phương pháp chính xác (câu trả lời được chấp nhận là không). –

+0

Tại sao và sự khác biệt này xảy ra như thế nào? Liên kết từng thư viện với lpthread là cách duy nhất để đảm bảo chúng nhất quán? – KyleL

Các vấn đề liên quan