xem xét mã nguồn sau đây, mà là hoàn toàn POSIX compliant:Làm thế nào để làm cho pthread_cond_timedwait() mạnh mẽ chống lại các thao tác đồng hồ hệ thống?
#include <stdio.h>
#include <limits.h>
#include <stdint.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/time.h>
int main (int argc, char ** argv) {
pthread_cond_t c;
pthread_mutex_t m;
char printTime[UCHAR_MAX];
pthread_mutex_init(&m, NULL);
pthread_cond_init(&c, NULL);
for (;;) {
struct tm * tm;
struct timeval tv;
struct timespec ts;
gettimeofday(&tv, NULL);
printf("sleep (%ld)\n", (long)tv.tv_sec);
sleep(3);
tm = gmtime(&tv.tv_sec);
strftime(printTime, UCHAR_MAX, "%Y-%m-%d %H:%M:%S", tm);
printf("%s (%ld)\n", printTime, (long)tv.tv_sec);
ts.tv_sec = tv.tv_sec + 5;
ts.tv_nsec = tv.tv_usec * 1000;
pthread_mutex_lock(&m);
pthread_cond_timedwait(&c, &m, &ts);
pthread_mutex_unlock(&m);
}
return 0;
}
In ngày hệ thống hiện tại mỗi 5 giây, tuy nhiên, nó hoạt động giấc ngủ của 3 giây giữa nhận được thời gian hệ thống hiện tại (gettimeofday
) và tình trạng chờ đợi (pthread_cond_timedwait
).
Ngay sau khi in "ngủ (...)", hãy thử đặt đồng hồ hệ thống hai ngày vào quá khứ. Chuyện gì xảy ra? Vâng, thay vì chờ thêm 2 giây nữa về điều kiện như thường lệ, pthread_cond_timedwait
hiện đang đợi hai ngày và 2 giây.
Làm cách nào để khắc phục điều đó?
Làm cách nào để tôi có thể viết mã tuân thủ POSIX, điều đó không bị ngắt khi người dùng thao tác đồng hồ hệ thống?
Hãy nhớ rằng đồng hồ hệ thống có thể thay đổi ngay cả khi không tương tác với người dùng (ví dụ: khách hàng NTP có thể tự động cập nhật đồng hồ mỗi ngày một lần). Đặt đồng hồ vào tương lai không thành vấn đề, nó sẽ chỉ khiến giấc ngủ thức dậy sớm, thường không có vấn đề gì và bạn có thể dễ dàng "phát hiện" và xử lý cho phù hợp, nhưng đặt đồng hồ vào quá khứ (ví dụ chạy trong tương lai, NTP phát hiện ra và sửa nó) có thể gây ra một vấn đề lớn.
PS:
Không phải pthread_condattr_setclock()
cũng không CLOCK_MONOTONIC
tồn tại trên hệ thống của tôi. Đó là bắt buộc đối với đặc tả POSIX 2008 (một phần của "Cơ sở") nhưng hầu hết các hệ thống vẫn chỉ tuân theo đặc tả POSIX 2004 tính đến hôm nay và trong đặc tả POSIX 2004 hai tùy chọn này là tùy chọn (Advanced Realtime Extension).
Tôi rất khó chịu vì hàm này có cấu trúc 'timespec' và sử dụng thời gian tuyệt đối. Tôi nghĩ rằng tôi sẽ sử dụng phương thức 'pipe()'/'select()' để thực hiện nó. – mpontillo