sleep、setitimer、alarm 三種方案在函數執行中設置 60 秒超時,時間到自動中斷該函數並返回/跳出。
| 方案 | 適用場景 | 精度 | 可中斷阻塞 IO | 可移植性 |
|---|---|---|---|---|
sleep(60) | 簡單延遲、無需中斷運算 | 秒級 | 否(僅阻塞當前執行緒) | POSIX / Windows (Sleep) |
alarm(60) + SIGALRM | 需中斷長時間運算/阻塞系統呼叫 | 秒級 | 是(信號中斷 read/accept 等) | POSIX(Linux/Unix) |
setitimer(ITIMER_REAL, ...) | 需微秒級精度、週期性定時 | 微秒級 | 是 | POSIX |
Windows CreateWaitableTimer + APC | Windows 原生高精度、可插隊 APC | 100ns | 是(佇列 APC) | Windows |
跨平台:pthread + 條件變數 / std::future (C++11) | 現代 C++、需取消點協作式取消 | 毫秒級 | 需代碼配合檢查取消標誌 | 全平台 |
sleep(60) 最簡單(僅延遲,不中斷運算中函數)#include <unistd.h> // POSIX
// Windows: #include <windows.h> -> Sleep(60000); // 毫秒
void long_running_task() {
// ... 大量運算 ...
}
int main() {
pid_t pid = fork();
if (pid == 0) { // 子程序執行任務
long_running_task();
exit(0);
} else { // 父程序計時
sleep(60);
kill(pid, SIGKILL); // 強制終止子程序
waitpid(pid, NULL, 0);
}
}
⚠️ 缺點: 需 fork 子程序,無法在同一進程中優雅中斷函數;Windows 無 fork。
alarm(60) + 信號處理器(POSIX 標準,可中斷阻塞呼叫)#include <signal.h>
#include <unistd.h>
#include <setjmp.h>
static sigjmp_buf env;
static volatile sig_atomic_t timed_out = 0;
void sigalrm_handler(int sig) {
timed_out = 1;
siglongjmp(env, 1); // 非局部跳轉回 main
}
int long_computation() {
// 模擬長時間運算
for (long long i = 0; i < 1e10; ++i) {
if (timed_out) return -1; // 協作式檢查(可選)
}
return 0;
}
int main() {
signal(SIGALRM, sigalrm_handler);
if (sigsetjmp(env, 1) == 0) {
alarm(60); // 60 秒後送 SIGALRM
int ret = long_computation();
alarm(0); // 取消鬧鐘
if (ret == -1) puts("Timed out!");
else puts("Done.");
} else {
puts("Timeout via signal!");
}
return 0;
}
⚠️ 注意: 信號處理器中只能呼叫 Async-signal-safe functions(siglongjmp、write、_exit 等),**嚴禁呼叫 printf, malloc, lock 等非安全函數**。
setitimer 微秒級精度(同信號機制)#include <sys/time.h>
struct itimerval timer = {
.it_value = { .tv_sec = 60, .tv_usec = 0 }, // 首次 60 秒
.it_interval = { 0, 0 } // 不重複
};
setitimer(ITIMER_REAL, &timer, NULL); // 同樣觸發 SIGALRM
// C11 threads
#include <threads.h>
#include <stdatomic.h>
atomic_bool cancel_flag = false;
int worker(void *arg) {
for (int i = 0; i < 1000000; ++i) {
if (atomic_load(&cancel_flag)) return -1; // 定期檢查
// do work
}
return 0;
}
int main() {
thrd_t t;
thrd_create(&t, worker, NULL);
thrd_sleep(&(struct timespec){.tv_sec=60}, NULL);
atomic_store(&cancel_flag, true);
int res;
thrd_join(t, &res);
return res;
}
sleep(60) / Sleep(60000)。alarm/setitimer + 信號(POSIX);Windows 用 CancelIoEx + 重疊 IO。atomic_bool)+ 定期檢查,最安全、可移植。std::future + std::async + wait_for,或 std::jthread (C++20) + request_stop()。總結: 沒有銀彈。**信號方案能真正中斷阻塞系統呼叫,但程式設計極難、不可移植、易產生資源洩漏**。現代開發強烈建議**協作式取消**:在長迴圈/阻塞點檢查原子旗標,配合 pthread_cancel (PTHREAD_CANCEL_DEFERRED) 或 C++ std::stop_token,安全又清晰。