Tại sao thời gian được báo cáo theo thời gian () đôi khi là 1 giây sau thành phần giây của timespec_get () trong mã C?


12

Đoạn mã sau:

struct timespec ts;
for (int x = 0; x < 100000000; x++) {
    timespec_get(&ts, TIME_UTC);
    long cTime = (long) time(NULL);
    if (cTime != ts.tv_sec && ts.tv_nsec < 3000000) {
        printf("cTime: %ld\n", cTime);
        printf("ts.tv_sec: %ld\n", ts.tv_sec);
        printf("ts.tv_nsec: %ld\n", ts.tv_nsec);
    }
}

tạo đầu ra này:

...
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2527419
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2534036
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2540359
cTime: 1579268059
ts.tv_sec: 1579268060
ts.tv_nsec: 2547039
...

Tại sao sự khác biệt giữa cTimets.tv_sec? Lưu ý rằng vấn đề không xảy ra nếu điều kiện được thay đổi thành ts.tv_nsec >= 3000000. Vấn đề phụ thuộc vào nano giây nhỏ hơn 3000000.


Bạn cần phải cụ thể hơn về hệ điều hành được sử dụng, phiên bản của nó, phiên bản của thư viện C được sử dụng.
Một số lập trình viên anh chàng

2
@Someprogrammerdude Linux Debian 8, GCC 6.3.0.
Theo

Có gì timespec_get()? Đây là C hay C ++? Vẻ thích std::timespec_get. Vui lòng sử dụng thẻ thích hợp.
Marco Bonelli

@MarcoBonelli: Nó đã được thêm vào C trong C11. Có thể sao chép trực tuyến .
ShadowRanger

@ShadowRanger cảm ơn bạn đã tham khảo, tôi không thể thấy một manmục timespec_gettrên hệ thống của mình nên tôi đã đi đến kết luận. Có ý nghĩa.
Marco Bonelli

Câu trả lời:


11

Lý do là, bạn (ngầm) sử dụng các đồng hồ hệ thống khác nhau. timespec_get()sử dụng đồng hồ thời gian thực toàn hệ thống độ phân giải cao , trong khi time()sử dụng thô đồng hồ thời gian thực .

Thử sử dụng

clock_gettime(CLOCK_REALTIME_COARSE, &ts);

thay vì của bạn timespec_get(), sau đó sự khác biệt sẽ biến mất.

Biên tập:

Điều này có thể được nhìn thấy trong Nguồn hạt nhân Linux, vclock_gettime.c

Quả thực vấn đề là một chút tinh tế để xem ở đây. Phần giây của các thành viên cấu trúc được sử dụng bởi CLOCK_REALTIME_COARSECLOCK_REALTIMEchứa các giá trị giống hệt nhau, nhưng phần nano giây là khác nhau; với CLOCK_REALTIMEnó có thể lớn hơn 1000000000(đó là một giây). Trong trường hợp này, nó được sửa trong cuộc gọi:

ts->tv_sec += __iter_div_u64_rem(ns, NSEC_PER_SEC, &ns);
ts->tv_nsec = ns;

Điều chỉnh này không được thực hiện với CLOCK_REALTIME_COARSE, cũng không phải với time(). Điều này giải thích sự khác biệt giữa CLOCK_REALTIMEtime().


Đây có phải là tài liệu ở bất cứ đâu, hoặc chỉ là một tạo tác timeđược thực hiện với đồng hồ (có lẽ là hiệu suất hơn) nhưng kém chính xác hơn (theo lý thuyết rằng dù sao nó cũng chỉ có độ chi tiết thứ hai, vậy ai cần độ chính xác)? Độ trễ thời gian thực khoảng một phần nghìn giây hoặc lâu hơn (các thử nghiệm trực tuyến cho thấy độ trễ thỉnh thoảng trên một ms, nhưng không nhiều hơn) khi bạn chỉ yêu cầu mức độ chi tiết thứ hai không phải là điều tôi quan trọng.
ShadowRanger

@ShadowRanger Tôi đã thêm một số chi tiết
Ctx

Không phải tài liệu rõ ràng về ý định, nhưng đó là đủ chi tiết cho một cuộc bỏ phiếu. :-) Thật buồn cười là đồng hồ thực sự có thể báo cáo giá trị hơn một giây của giây.
ShadowRanger

@ShadowRanger Tôi không thể tìm thấy một tài liệu thực sự ngoài nguồn cho điều đó, điều đó cũng có nghĩa là hành vi cũng có thể thay đổi chi tiết mà không cần thông báo trước
Ctx

@Ctx Cảm ơn bạn đã trả lời chi tiết! Tôi sẽ sử dụng timespec_get () thay vì clock_gettime () mà bạn khuyên, vì timespec_get () là C11 thay vì POSIX và không yêu cầu cài đặt đồng hồ nào sẽ sử dụng. Tôi không biết các đồng hồ khác nhau đã được sử dụng, nhưng được lựa chọn, tôi không thấy nhiều điểm trong việc sử dụng đồng hồ thô.
Theo
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.