為什麼用 SIGINT 可能比 SIGALRM 好的幾個原因
1. Flexibility
SIGINT 不需要將時間間隔寫進程式
可以透過系統的殼層腳本觸發
隨情況調整觸發的頻率跟是否要觸發
這有助於程式的彈性和降低重新編譯的次數
甚至可能之後
想要對寫好的程式進行 profile
去計算 cache miss rate 等等
就可以免去 SIGALRM 開銷帶來的副作用
因此 SIGINT 可以說是方便很多
在很多時候會有意想不到的好處
2. Stability
A. Timer Inheritance 計時器繼承
fork() / exec()-s:
POSIX 標準規定使用 alarm() 觸發計時器時
在往後調用 fork() 的時候會清除
在往後調用 exec() 系列函數的時候
保留剩餘的時間到下一個行程映像持續計算
Alarms created by alarm are preserved across execve
and are not inherited by children created via fork.
然而標準對 signal disposition 卻有不同的邏輯
在 fork() 的時候被繼承
在 exec() 的時候卻會被重設成預設的 handler
A child created via fork inherits a copy of its
parent's signal dispositions. During an execve,
the dispositions of handled signals are reset to
the default; the dispositions of ignored signals
are left unchanged.
不一致的設計潛在隱患
可能導致非常難以除錯或是異常的行為
B. Timer Anomaly 計時器異常
除此之外
Linux 對 setitimer() 的異常行為有以下的描述:
The generation and delivery of a signal are distinct,
and only one instance of each of the signals listed
above may be pending for a process. Under very heavy
loading, an ITIMER_REAL timer may expire before the
signal from a previous expiration has been delivered.
The second signal in such an event will be lost.
ITIMER_REAL 觸發的是 SIGALRM
如果要避免上述的問題
可以採用 ITIMER_VIRTUAL 計時器
而它相對應的信號是 SIGVTALRM
但是它的時間不再是 wall time (real time)
而是 execution time
C. Unspecified Interactions 未定義行為
sleep(), usleep(), ualarm(), setitimer():
根據 POSIX 的標準
所有的計時器都是 per-process basis
而且不會 stack 起來
所以設定新的計時器會覆蓋舊有的計時器
因此每次檢查 alarm 的返回值至關重要
不然可能導致不再有 SIGALRM 被觸發
3. Conclusions
計時器的設定有很多瑣碎的細節
甚至可能有上述我沒想到的更隱晦的
都可能在一個不經意的情況
讓程式運作的不如預期
除非真的很需要計時器這種對時間很要求的情況
才有使用的必要
如果只是想要看看目前執行的進度
定期寫記錄到硬碟或 SIGINT 不失為一個好方法
※ 引述《BreathWay (息尉)》之銘言:
: 標題: [問題] 如何設定時間上限使程式自動輸出?
: 時間: Sat Dec 30 11:04:55 2017
:
: 問題(Question):
: 我寫了一個以暴力演算法求最佳解的程式,
: 主要是透過不斷更新所找到的更好的解來達成。
: 但是我希望能設定一個時間上限,
: 如果程式還沒跑完就直接輸出目前找到的最好的解。
: 請問有辦法在 C 裡面實作這個功能嗎?
:
: 推 Hazukashiine: POSIX Thread 或是 Signal Handler 12/30 14:32
: → Hazukashiine: 像是可以 SIGINT 時印出 ex. ping 12/30 14:34
: → Hazukashiine: 事實上你可以搭配 Linux 的 cron (job scheduler) 12/30 22:35
: → Hazukashiine: 來達成定時發送 SIGINT 的任務 不一定要人親自去按 12/30 22:35
: → galic: Ctrl+C只是其中一種Signal(SIGINT)好嗎 然後推文為何一直叫 12/30 23:01
: → galic: 人家用SIGINT 明明就有timer用的signal 12/30 23:01
: → galic: 你也只有polling counter或是透過timer兩種作法 12/30 23:03
: → galic: 但照po後來的回覆 這種需求就是要走timer阿 12/30 23:06
: → galic: 那就看一看timer的文件 https://tinyurl.com/lo9e3w3 12/30 23:08
: → galic: https://tinyurl.com/d5fw2rh 12/30 23:09
: → Hazukashiine: 用 SIGINT 是因為方便 彈性比較高 可以搭配腳本使用 12/30 23:40
: → Hazukashiine: 如果程式正在前景跑 但是手癢想在 timer expired 12/30 23:40
: → Hazukashiine: 前看偷看 按一下 ctrl + c 就可以了 如果想要靜靜放 12/30 23:40
: → Hazukashiine: 後景跑 就指令後面加 & 如果直接用樓上的方法寫死在 12/30 23:40
: → Hazukashiine: 程式裡編譯好的話 就沒有這種好處了 更何況樓主可能 12/30 23:40
: → Hazukashiine: 只是想偶爾偷看一下進度而已 我覺得用 SIGINT 合適 12/30 23:40
: → galic: 不用幫別人腦補 12/30 23:49