41. clock_nanosleep - 高精度睡眠
函數介紹
clock_nanosleep
系統調用提供納秒級精度的睡眠功能,支持絕對時間和相對時間兩種模式,比傳統的nanosleep
更加靈活。
函數原型
#include <time.h>int clock_nanosleep(clockid_t clock_id, int flags,const struct timespec *request,struct timespec *remain);
功能
使進程睡眠指定的時間,支持高精度納秒級睡眠。
參數
clockid_t clock_id
: 時鐘IDint flags
: 標志位0
: 相對時間睡眠TIMER_ABSTIME
: 絕對時間睡眠
const struct timespec *request
: 請求睡眠的時間struct timespec *remain
: 剩余時間(被信號中斷時)
返回值
- 成功時返回0
- 被信號中斷時返回-1,并設置errno為EINTR
- 失敗時返回-1,并設置其他errno
相似函數
nanosleep()
: 納秒級睡眠sleep()
: 秒級睡眠usleep()
: 微秒級睡眠
示例代碼
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <signal.h>
#include <unistd.h>// 信號處理函數
void signal_handler(int sig) {printf(" 接收到信號 %d\n", sig);
}int main() {struct timespec request, remain, start, end;int result;printf("=== Clock_nanosleep 函數示例 ===\n");// 示例1: 相對時間睡眠printf("\n示例1: 相對時間睡眠\n");// 睡眠100毫秒request.tv_sec = 0;request.tv_nsec = 100000000; // 100毫秒 = 100,000,000納秒if (clock_gettime(CLOCK_MONOTONIC, &start) == -1) {perror(" 獲取開始時間失敗");}printf(" 開始睡眠: %ld.%09ld 秒\n", start.tv_sec, start.tv_nsec);result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);if (result == -1) {if (errno == EINTR) {printf(" 睡眠被信號中斷\n");} else {printf(" 睡眠失敗: %s\n", strerror(errno));}} else {printf(" 睡眠完成\n");if (clock_gettime(CLOCK_MONOTONIC, &end) == -1) {perror(" 獲取結束時間失敗");} else {long long actual_sleep = (end.tv_sec - start.tv_sec) * 1000000000LL + (end.tv_nsec - start.tv_nsec);printf(" 實際睡眠時間: %lld 納秒\n", actual_sleep);}}// 示例2: 絕對時間睡眠printf("\n示例2: 絕對時間睡眠\n");// 獲取當前時間if (clock_gettime(CLOCK_REALTIME, &start) == 0) {printf(" 當前時間: %ld.%09ld 秒\n", start.tv_sec, start.tv_nsec);// 設置絕對睡眠時間(當前時間+2秒)struct timespec absolute_time;absolute_time.tv_sec = start.tv_sec + 2;absolute_time.tv_nsec = start.tv_nsec;printf(" 絕對睡眠時間: %ld.%09ld 秒\n", absolute_time.tv_sec, absolute_time.tv_nsec);result = clock_nanosleep(CLOCK_REALTIME, TIMER_ABSTIME, &absolute_time, NULL);if (result == -1) {if (errno == EINTR) {printf(" 絕對時間睡眠被信號中斷\n");} else {printf(" 絕對時間睡眠失敗: %s\n", strerror(errno));}} else {printf(" 絕對時間睡眠完成\n");}}// 示例3: 被信號中斷的睡眠printf("\n示例3: 被信號中斷的睡眠\n");// 設置信號處理signal(SIGUSR1, signal_handler);// 啟動另一個線程發送信號pid_t pid = fork();if (pid == 0) {// 子進程:延遲發送信號sleep(1);kill(getppid(), SIGUSR1);exit(0);} else if (pid > 0) {// 父進程:長時間睡眠request.tv_sec = 5;request.tv_nsec = 0;printf(" 開始5秒睡眠,1秒后會被信號中斷\n");result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, &remain);if (result == -1 && errno == EINTR) {printf(" 睡眠被信號中斷\n");printf(" 剩余時間: %ld.%09ld 秒\n", remain.tv_sec, remain.tv_nsec);}wait(NULL); // 等待子進程結束}// 示例4: 錯誤處理演示printf("\n示例4: 錯誤處理演示\n");// 使用無效的時鐘IDrequest.tv_sec = 1;request.tv_nsec = 0;result = clock_nanosleep(999, 0, &request, NULL);if (result == -1) {if (errno == EINVAL) {printf(" 無效時鐘ID錯誤處理正確: %s\n", strerror(errno));}}// 使用無效的時間值request.tv_sec = -1;request.tv_nsec = 0;result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);if (result == -1) {if (errno == EINVAL) {printf(" 無效時間值錯誤處理正確: %s\n", strerror(errno));}}// 使用過大的納秒值request.tv_sec = 0;request.tv_nsec = 1000000000; // 10億納秒 = 1秒,但應該 < 1秒result = clock_nanosleep(CLOCK_MONOTONIC, 0, &request, NULL);if (result == -1) {if (errno == EINVAL) {printf(" 納秒值過大錯誤處理正確: %s\n", strerror(errno));}}// 示例5: 不同時鐘的睡眠效果printf("\n示例5: 不同時鐘的睡眠效果\n");printf("CLOCK_REALTIME睡眠:\n");printf(" - 基于系統實時時間\n");printf(" - 受系統時間調整影響\n");printf(" - 適用于絕對時間睡眠\n\n");printf("CLOCK_MONOTONIC睡眠:\n");printf(" - 基于單調遞增時間\n");printf(" - 不受系統時間調整影響\n");printf(" - 適用于相對時間睡眠\n\n");// 示例6: 高精度定時器演示printf("示例6: 高精度定時器演示\n");printf("創建100毫秒間隔的定時器循環:\n");struct timespec interval;interval.tv_sec = 0;interval.tv_nsec = 100000000; // 100毫秒for (int i = 0; i < 5; i++) {if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {printf(" 第%d次: 時間 %ld.%09ld\n", i+1, start.tv_sec, start.tv_nsec);}result = clock_nanosleep(CLOCK_MONOTONIC, 0, &interval, NULL);if (result == -1) {if (errno == EINTR) {printf(" 第%d次: 睡眠被中斷\n", i+1);break;}}}// 示例7: 睡眠精度測試printf("\n示例7: 睡眠精度測試\n");struct timespec sleep_times[] = {{0, 1000}, // 1微秒{0, 10000}, // 10微秒{0, 100000}, // 100微秒{0, 1000000}, // 1毫秒{0, 10000000}, // 10毫秒{0, 100000000}, // 100毫秒{1, 0} // 1秒};const char *time_labels[] = {"1微秒", "10微秒", "100微秒", "1毫秒", "10毫秒", "100毫秒", "1秒"};printf("睡眠精度測試結果:\n");for (int i = 0; i < 7; i++) {if (clock_gettime(CLOCK_MONOTONIC, &start) == 0) {result = clock_nanosleep(CLOCK_MONOTONIC, 0, &sleep_times[i], NULL);if (clock_gettime(CLOCK_MONOTONIC, &end) == 0) {long long actual = (end.tv_sec - start.tv_sec) * 1000000000LL + (end.tv_nsec - start.tv_nsec);long long requested = sleep_times[i].tv_sec * 1000000000LL + sleep_times[i].tv_nsec;long long diff = actual - requested;printf(" %-8s: 請求%8lld ns, 實際%8lld ns, 誤差%+6lld ns\n",time_labels[i], requested, actual, diff);}}}// 示例8: 實際應用場景printf("\n示例8: 實際應用場景\n");// 場景1: 實時系統定時printf("場景1: 實時系統定時\n");printf("在實時應用中確保精確的時間間隔\n");// 場景2: 性能基準測試printf("\n場景2: 性能基準測試\n");printf("提供精確的延遲控制用于性能測試\n");// 場景3: 動畫和游戲循環printf("\n場景3: 動畫和游戲循環\n");printf("維持穩定的幀率和更新頻率\n");// 場景4: 網絡超時控制printf("\n場景4: 網絡超時控制\n");printf("實現精確的網絡操作超時機制\n");printf("\n總結:\n");printf("clock_nanosleep提供納秒級精度的睡眠功能\n");printf("支持相對時間和絕對時間兩種模式\n");printf("比傳統sleep函數更加靈活和精確\n");printf("正確處理信號中斷和剩余時間計算\n");printf("適用于需要高精度時間控制的應用場景\n");return 0;
}
42. clock_settime - 設置時鐘時間
函數介紹
clock_settime
系統調用用于設置指定時鐘的時間值。它允許程序修改系統時鐘,主要用于時間同步和系統管理。
函數原型
#include <time.h>int clock_settime(clockid_t clk_id, const struct timespec *tp);
功能
設置指定時鐘的時間值。
參數
clockid_t clk_id
: 時鐘ID(通常為CLOCK_REALTIME)const struct timespec *tp
: 指向timespec結構體的指針,包含新的時間值
返回值
- 成功時返回0
- 失敗時返回-1,并設置errno
特殊限制
- 需要CAP_SYS_TIME能力或root權限
- 通常只能設置CLOCK_REALTIME時鐘
相似函數
settimeofday()
: 設置系統時間stime()
: 設置系統時間(已廢棄)
示例代碼
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>int main() {struct timespec current_time, new_time;int result;printf("=== Clock_settime 函數示例 ===\n");printf("當前用戶 UID: %d\n", getuid());printf("當前有效 UID: %d\n", geteuid());// 示例1: 獲取當前時間printf("\n示例1: 獲取當前時間\n");if (clock_gettime(CLOCK_REALTIME, ¤t_time) == -1) {perror(" 獲取當前時間失敗");} else {printf(" 當前系統時間: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);printf(" 對應日期: %s", ctime(¤t_time.tv_sec));}// 示例2: 權限檢查printf("\n示例2: 權限檢查\n");// 嘗試設置時間(通常會失敗)new_time.tv_sec = current_time.tv_sec;new_time.tv_nsec = current_time.tv_nsec;result = clock_settime(CLOCK_REALTIME, &new_time);if (result == -1) {if (errno == EPERM) {printf(" 權限不足設置時間: %s\n", strerror(errno));printf(" 說明: 需要CAP_SYS_TIME能力或root權限\n");} else {printf(" 設置時間失敗: %s\n", strerror(errno));}} else {printf(" 時間設置成功\n");}// 示例3: 錯誤處理演示printf("\n示例3: 錯誤處理演示\n");// 使用無效的時鐘IDresult = clock_settime(999, &new_time);if (result == -1) {if (errno == EINVAL) {printf(" 無效時鐘ID錯誤處理正確: %s\n", strerror(errno));}}// 使用無效的時間值struct timespec invalid_time;invalid_time.tv_sec = -1;invalid_time.tv_nsec = 0;result = clock_settime(CLOCK_REALTIME, &invalid_time);if (result == -1) {if (errno == EINVAL) {printf(" 無效時間值錯誤處理正確: %s\n", strerror(errno));}}// 使用過大的納秒值invalid_time.tv_sec = current_time.tv_sec;invalid_time.tv_nsec = 1000000000; // 10億納秒,應該 < 1秒result = clock_settime(CLOCK_REALTIME, &invalid_time);if (result == -1) {if (errno == EINVAL) {printf(" 納秒值過大錯誤處理正確: %s\n", strerror(errno));}}// 使用NULL指針result = clock_settime(CLOCK_REALTIME, NULL);if (result == -1) {if (errno == EFAULT) {printf(" NULL指針錯誤處理正確: %s\n", strerror(errno));}}// 示例4: 支持的時鐘類型printf("\n示例4: 支持的時鐘類型\n");printf("CLOCK_REALTIME:\n");printf(" - 系統實時鐘\n");printf(" - 可以被設置\n");printf(" - 用于表示當前時間\n\n");printf("其他時鐘類型:\n");printf(" - CLOCK_MONOTONIC: 通常不能設置\n");printf(" - CLOCK_PROCESS_CPUTIME_ID: 不能設置\n");printf(" - CLOCK_THREAD_CPUTIME_ID: 不能設置\n\n");// 示例5: 時間格式轉換printf("示例5: 時間格式轉換\n");if (clock_gettime(CLOCK_REALTIME, ¤t_time) == 0) {printf(" 當前時間: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);// 從日期字符串轉換為time_tstruct tm time_info;strptime("2024-01-01 12:00:00", "%Y-%m-%d %H:%M:%S", &time_info);time_t new_time_t = mktime(&time_info);printf(" 轉換時間: %s", ctime(&new_time_t));// 轉換為timespec格式struct timespec converted_time;converted_time.tv_sec = new_time_t;converted_time.tv_nsec = 0;printf(" timespec格式: %ld.%09ld 秒\n", converted_time.tv_sec, converted_time.tv_nsec);}// 示例6: 時區考慮printf("\n示例6: 時區考慮\n");if (clock_gettime(CLOCK_REALTIME, ¤t_time) == 0) {printf(" UTC時間: %ld.%09ld 秒\n", current_time.tv_sec, current_time.tv_nsec);// 獲取本地時區偏移struct tm *utc_tm = gmtime(¤t_time.tv_sec);struct tm *local_tm = localtime(¤t_time.tv_sec);time_t utc_time = mktime(utc_tm);time_t local_time = mktime(local_tm);long tz_offset = local_time - utc_time;printf(" 時區偏移: %+ld 秒\n", tz_offset);}// 示例7: 安全考慮printf("\n示例7: 安全考慮\n");printf("使用clock_settime的安全注意事項:\n");printf("1. 需要適當的權限(CAP_SYS_TIME或root)\n");printf("2. 不當的時間設置可能影響系統穩定性\n");printf("3. 時間跳躍可能影響依賴時間的應用程序\n");printf("4. 應該使用NTP等標準時間同步服務\n");printf("5. 在生產環境中謹慎使用\n\n");// 示例8: 實際應用場景printf("示例8: 實際應用場景\n");// 場景1: NTP客戶端printf("場景1: NTP客戶端\n");printf(" - 從NTP服務器獲取時間\n");printf(" - 調整系統時鐘\n");printf(" - 保持時間同步\n\n");// 場景2: 系統初始化printf("場景2: 系統初始化\n");printf(" - 設置初始系統時間\n");printf(" - 從硬件時鐘同步\n");printf(" - 恢復時間設置\n\n");// 場景3: 調試和測試printf("場景3: 調試和測試\n");printf(" - 設置特定時間進行測試\n");printf(" - 模擬時間相關場景\n");printf(" - 性能基準測試\n\n");// 場景4: 時間同步服務printf("場景4: 時間同步服務\n");printf(" - 分布式系統時間協調\n");printf(" - 數據庫事務時間戳\n");printf(" - 日志時間同步\n\n");// 示例9: 替代方案printf("示例9: 替代方案\n");printf("現代時間管理推薦使用:\n");printf("1. NTP守護進程(ntpd)\n");printf("2. systemd-timesyncd\n");printf("3. chrony\n");printf("4. chronyd\n");printf("5. 避免手動設置系統時間\n\n");printf("總結:\n");printf("clock_settime用于設置系統時鐘時間\n");printf("需要適當的權限才能使用\n");printf("主要用于時間同步服務\n");printf("不當使用可能影響系統穩定性\n");printf("推薦使用標準的時間同步服務\n");return 0;
}