[英]What does "wait and waitpid are always interrupted when a signal is caught" mean?
從APUE :
為了防止應用程序不得不處理中斷的系統調用,4.2BSD 引入了某些中斷系統調用的自動重啟。 被自動重新啟動該系統調用
ioctl
,read
,readv
,write
,writev
,wait
,和waitpid
。 正如我們所提到的,這些功能中的前五個功能只有在它們在慢速設備上運行時才會被信號中斷; 當捕捉到信號時,wait
和waitpid
總是被中斷。 由於這會導致一些應用程序出現問題,如果操作被中斷,則不希望操作重新啟動,4.3BSD 允許進程在每個信號的基礎上禁用此功能。
是不是說在引入自動重啟之前,如果進程捕捉到信號, wait
和waitpid
會立即停止等待並執行后續代碼?
例如:
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
void handler(int sig){}
void handler2(int sig){}
int main(){
pid_t pid;
int status;
signal(SIGUSR1, handler);
signal(SIGUSR2, handler2);
if((pid == fork()) < 0){
printf("fork error\n");
}else{
if(pid){
//child
//do something, needs several hours.
}else{
//parent
waitpid(pid, &status, 0);
printf("Hello world\n");
}
}
return 0;
}
如果不提供自動重啟,當我在后台運行這個程序時gcc test.c && ./a.out &
,然后我發送一個信號kill -SIGUSR1 pid
或kill -SIGUSR2 pid
, waitpid
將返回, waitpid(pid, &status, 0);
會執行。
如果提供自動重新啟動, waitpid
將再次執行並且父waitpid
將保持等待。
我的理解正確嗎?
signal()
(System-V 語義)的原始行為是,如果進程當前處於睡眠狀態,則中斷任何系統調用,執行信號處理程序並且系統調用以-EINTR
返回。 然后,BSD4.3 發明了重啟機制,它會在任何系統調用被中斷后自動重啟。 如果涉及信號處理程序,這避免了必須為每個系統調用編寫循環。
Linux 沒有改變signal()
系統調用的語義。 然而,現在的signal()
glibc 包裝函數默認調用帶有SA_RESTART
標志的系統調用sigaction()
。 所以,如果你不需要重新啟動行為,你要調用sigaction()
並忽略該標志。
所以,你的代碼確實在 BSD 和 linux 上都使用了重啟機制
wait
和waitpid
像任何其他阻塞函數一樣可以在errno
設置為EINTR
被中斷——這正是因為信號處理程序可以做的很少——主要是設置一些標志。 現在,如果阻塞函數不會以EINTR
返回,你怎么能以任何方式對信號做出反應?!
但這也意味着您需要對每個函數進行復雜的循環——您可能有一些您知道不希望系統調用被中斷的信號,因此您可以將此信號設置為自動重啟。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.