讀取方式
通過ioctl
#include <linux/rtc.h> int ioctl(fd, RTC_request, param);hwclock命令
通常內核在boot以及從低電量中恢復時,會讀取RTC更新system time
軟件時鐘
HZ and jiffies, 由內核維護,對於PC通常HZ配置為 1s / 10ms = 100
精度影響select等依賴timeout的系統調用
HRT(high-resolution timers). Linux 2.6.21開始,內核支持高精度定時器,不受內核jiffy限制,可以達到硬件時鐘的精度。
外部時鐘
從網絡ntp,原子鐘等同步
real time => 從某個時間點(比如Epoch)開始的系統時間
sys and user time => 通常指程序在內核態和用戶態花的時間
時間的表示
time_t 從Epoch開始的秒數
calendar time 字符串
拆分時間 struct tm
struct tm { int tm_sec; /* seconds */ int tm_min; /* minutes */ int tm_hour; /* hours */ int tm_mday; /* day of the month */ int tm_mon; /* month */ int tm_year; /* year */ int tm_wday; /* day of the week */ int tm_yday; /* day in the year */ int tm_isdst; /* daylight saving time */ };struct timeval/struct timespec
[code]struct timeval { time_t seconds; suseconds_t useconds; } struct timespec { time_t tv_sec; /* seconds */ long tv_nsec; /* nanoseconds */ };
[code]#include <time.h> #include <sys/time.h> // number of seconds since epoch time_t time(time_t *t) //參數time_t* char *ctime(const time_t *timep); char *ctime_r(const time_t *timep, char *buf); struct tm *gmtime(const time_t *timep); struct tm *gmtime_r(const time_t *timep, struct tm *result); struct tm *localtime(const time_t *timep); struct tm *localtime_r(const time_t *timep, struct tm *result); //參數struct tm* char *asctime(const struct tm *tm); char *asctime_r(const struct tm *tm, char *buf); time_t mktime(struct tm *tm); int gettimeofday(struct timeval *tv, struct timezone *tz);//如果系統時間調整了會影響 int clock_gettime(clockid_t clk_id, struct timespec *tp); //將tm按照format處理後放到s size_t strftime(char *s, size_t max, const char *format, const struct tm *tm); //將字符串時間s按照format格式化後放入tm char *strptime(const char *s, const char *format, struct tm *tm);
[code]unsigned int sleep(unsigned int seconds);
usleep
[code]int usleep(useconds_t usec);nanosleep
[code]int nanosleep(const struct timespec *req, struct timespec *rem);alarm
[code]// SIGALARM after seconds unsigned int alarm(unsigned int seconds);timer_create
[code]int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);timerfd_create => 可以用select/poll/epoll監聽
[code]int timerfd_create(int clockid, int flags);select
[code]// struct timeval可以精確到微秒(如果硬件有高精度時鐘支持) int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); // struct timespec可以精確到納秒,但是pselect下次無法修改timeout int pselect(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, const struct timespec *timeout, const sigset_t *sigmask); // 一般能提供周期,延時,時間點觸發,但核心還是時間點觸發的timer // 1.call_period => 觸發一次重新注冊call_at // 2.call_later => 轉換為call_at // 3.call_at => 時間點觸發的timer可以用一個優先級隊列保存poll
[code]// timeout最小單位ms,並且rounded up to系統時鐘的精度 int poll(struct pollfd *fds, nfds_t nfds, int timeout); // 注意timespec會被轉換成ms int ppoll(struct pollfd *fds, nfds_t nfds, const struct timespec *timeout_ts, const sigset_t *sigmask);epoll
[code]// timeout最小單位ms,並且rounded up to系統時鐘的精度 int epoll_wait(int epfd, struct epoll_event *events, int maxevents, int timeout); int epoll_pwait(int epfd, struct epoll_event *events, int maxevents, int timeout, const sigset_t *sigmask);
沒有全局時鐘是分布式系統需要一致性算法的一個重要原因,因為我們沒辦法根據單機的系統時間戳來判斷多台機器之間事件的先後順序,那麼對於一個新的節點,我們要把之前所有的時間atomic broadcast到這個新節點就會出現問題,所以這也是分布式一致性算法(Paxos/Raft/Viewstamp Replication/Zab)解決的一個問題,當然再加上網絡的異步,以及無法獲知各個節點的全局狀態,以及機器crash等各種問題,這些算法往往加入了容錯性。