2012-10-08 38 views
10

Tôi đang phát triển máy chủ trò chơi, được viết trên C. Và tôi cần phát triển một chu kỳ với tần suất nhất định (50 lần mỗi giây) để thực hiện thuật toán. Vấn đề là tôi không thể tạm dừng chương trình trong khoảng thời gian chính xác - 20000 micro giây. Chức năng usleep(20000) chạy khoảng 30000 micro giây. Kết quả luôn cao hơn 10000 micro giây so với dự kiến.delay time in C. usleep

Dưới đây là ví dụ đơn giản của tôi mã:

#include <stdio.h> 
#include <time.h> 
#include <unistd.h> 

int main(int argc, char ** argv) 
{ 

     const unsigned long long nano = 1000000000; 
     unsigned long long t1, t2; 

     struct timespec tm; 

     for(;;) 
     { 

       clock_gettime(CLOCK_REALTIME, &tm); 
       t1 = tm.tv_nsec + tm.tv_sec * nano; 

       usleep(20000); 

       clock_gettime(CLOCK_REALTIME, &tm); 
       t2 = tm.tv_nsec + tm.tv_sec * nano; 

       printf("delay: %ld\n", (t2 - t1)/1000); 
     } 

     return 0; 

} 

Và kết quả của nó đang chạy:

$ ./a.out 
delay: 29233 
delay: 29575 
delay: 29621 
delay: 29694 
delay: 29688 
delay: 29732 
delay: 29709 
delay: 29706 
delay: 29666 
delay: 29702 
delay: 29702 
delay: 29705 
delay: 29789 
delay: 29619 
delay: 29785 
delay: 29634 
delay: 29692 
delay: 29708 
delay: 29701 
delay: 29703 

Tôi cũng đã cố gắng để sử dụng chức năng select(), nhưng kết quả cũng tương tự như với sleep() .

Giải thích cho tôi, vui lòng, với mã của tôi có vấn đề gì.

ps:

$ uname -a 
FreeBSD home.com 9.0-RELEASE FreeBSD 9.0-RELEASE #0: Tue Jan 3 07:46:30 UTC 2012  [email protected]:/usr/obj/usr/src/sys/GENERIC amd64 
+0

Liên quan: [Ngủ trong một khoảng thời gian chính xác] (http://stackoverflow.com/q/5209408/237483) –

Trả lời

9

Thay vì ngủ cho 20000 useconds, giấc ngủ cho thời gian còn lại cho đến khi bạn muốn chạy một lần nữa, dựa trên các cuộc gọi đến clock_gettime

Ie:

usleep(lasttime+20000-now); // But make sure you don't sleep when the result is negative 

Nó không phải là mã của bạn có một vấn đề, nhưng các cuộc gọi thực tế để ngủ, đọc thời gian, vv mất thời gian, và hệ thống không thể ngủ cho thời gian chính xác anyway, trừ khi nó là một bội số của nó chính xác chu kỳ đồng hồ

11

Chức năng ngủ trên hệ thống không theo thời gian thực không được đảm bảo để ngủ đúng khoảng thời gian được chỉ định; trên một hệ thống bận rộn, quá trình sẽ được đánh thức chỉ khi lát thời gian của nó bắt đầu. Hoặc, as the man page puts it, "hoạt động của hệ thống có thể kéo dài giấc ngủ bằng một số tiền không xác định".

Số tiền gần 10ms nghe có vẻ như tần số kern.hz được hạ xuống 100, as some recommend for VM setups.

Giải pháp cổ điển cho vấn đề này là giải pháp do Ofir cung cấp: thay vì chỉ định khoảng thời gian ngủ cố định, hãy chỉ định thời gian còn lại để ngủ. Trung bình, vòng lặp của bạn sẽ chạy mỗi 20ms, đó là những gì bạn có khả năng muốn đạt được nhất.

+5

Để thêm vào câu trả lời: các lệnh ngủ sẽ giải phóng bộ xử lý trong một khoảng thời gian đã đặt. Trong thời gian trì hoãn này, quy trình không yêu cầu bộ xử lý và không phải là một phần của cuộc bầu cử quá trình lên lịch. Khi bộ đếm thời gian hết hạn, quá trình sẽ trở lại cạnh tranh với quá trình khác để sử dụng CPU. Sự chậm trễ bổ sung xuất phát từ sự lựa chọn của người lên lịch để chọn chương trình của bạn hay không tại mỗi thời điểm bầu cử. –