基於 alarm()、pause()、sigaction() 實現可重入的 mysleep(),並分析信號處理中可能出現的競態條件與優化方案。
| 函數 | 參數 | 返回值 |
|---|---|---|
alarm(seconds) | unsigned int | 0 或剩餘秒數 |
pause() | void | 僅出錯返回 -1 (errno=EINTR) |
sigaction(signo, &act, &oact) | int, struct sigaction*, struct sigaction* | 成功 0,失敗 -1 |
struct sigaction {
void (*sa_handler)(int); // 傳統處理函數
void (*sa_sigaction)(int, siginfo_t*, void*); // 擴充處理函數 (SA_SIGINFO)
sigset_t sa_mask; // 處理期間暫時阻塞的信號集
int sa_flags; // SA_RESTART, SA_NODEFER, SA_RESETHAND 等
void (*sa_restorer)(void); // 已棄用
};
#include
#include
void myhandler(int sig) {} // 空處理函數,僅為中斷 pause
int mysleep(int timeout) {
struct sigaction act, oact;
act.sa_handler = myhandler;
sigemptyset(&act.sa_mask);
act.sa_flags = 0;
sigaction(SIGALRM, &act, &oact); // 註冊 SIGALRM 處理
alarm(timeout); // 設定鬧鐘
pause(); // 等待信號
int ret = alarm(0); // 取消鬧鐘,獲取剩餘秒數
sigaction(SIGALRM, &oact, NULL); // 恢復原處理
return ret;
}
int main() {
while (1) {
printf("mysleep start...\n");
mysleep(3);
printf("mysleep success\n");
}
return 0;
}
main 呼叫 mysleep → 註冊 SIGALRM 處理函數 myhandler (預設動作為終止進程,必須覆蓋)。alarm(timeout) 設定核心定時器。pause() 讓進程睡眠,核心切換至其他進程。SIGALRM 給進程。SIGALRM,執行 myhandler (信號自動屏蔽/解除屏蔽)。myhandler 返回 → sigreturn 系統調用 → 回用戶態繼續 pause() 後指令 (alarm(0))。alarm() 後、pause() 前進程收到其他信號並執行處理函數,pause() 可能提前返回,導致睡眠時間不足。pause() 僅阻塞呼叫執行緒,其他執行緒繼續運行。alarm() 與 setitimer() 共用實時定時器,相互覆蓋。nanosleep() (POSIX.1b) 替代,無信號副作用、奈秒精度、可被信號中斷並返回剩餘時間結構體。sa_flags = SA_RESTART 讓系統自動重啟被中斷的系統調用 (部分系統不支援 pause)。sigprocmask() 封鎖 SIGALRM 避免競態。教學用途理解信號機制足夠,生產環境請優先使用 nanosleep / clock_nanosleep / std::this_thread::sleep_for 等高階 API。