訊號是非同步,它會在程式的任何地方發生。由此程式正常的執行路徑被打破,去執行訊號處理函數。
一般情況下
,進程正在執行某個系統調用,那麼在該系統調用返回前訊號是不會被遞送的。但慢速系統調用除外,如讀寫終端、網路、磁碟,以及wait和pause。這些系
統調用都會返回-1,errno置為EINTR當系統調用被中斷時,我們可以選擇使用迴圈再次調用,或者設定重新啟動該系統調用
(SA_RESTART)。
現在說說對上面話的理解:
我認為函數或進程的運行最終都迴歸結尾系統調用,(呵呵,非官方,自己理解)
那麼
“進程正在執行某個系統調用,那麼在該系統調用返回前訊號是不會被遞送的”,就是說大多數進程在運行期間是阻塞訊號的,系統調用完再處理,
但是(以下引用APUE):如果在進程執行一個低速系統而阻塞期間捕捉到一個訊號,該系統調用被終端不再繼續執行
When a system call is slow and a signal arrives while it was blocked,
waiting for something, the call is aborted and returns -EINTR
,
so that the library function will return -1 and set errno
to EINTR
. Just before the system call returns, the user program's
signal handler is called.
(So, what is "slow"? Mostly those calls that can block forever waiting
for external events; read and write to terminal devices, but not
read and write to disk devices, wait
, pause
.)
This means that a system call can return an error while nothing was
wrong. Usually one will want to redo the system call. That can be
automated by installing the signal handler using a call to
sigaction
with the SA_RESTART
flag set.
The effect is that upon an interrupt the system call is aborted,
the user program's signal handler is called, and afterwards
the system call is restarted from the beginning.
我們可以選擇使用迴圈再次調用,或者設定重新啟動該系統調用
(SA_RESTART),
這是是低速系統調用被訊號中斷的解決辦法,1迴圈2SA——RESTART
好啦,實驗代碼:
#include <stdio.h>
2 #include <stdlib.h>
3 #include <unistd.h>
4 #include <stdbool.h>
5 #include <signal.h>
6 #include <sys/types.h>
7 #include <errno.h>
8 #include <string.h>
9
10 void int_handler (int signum)
11 {
12 printf ("int handler %d/n",signum);
13 }
14
15 int main(int argc, char **argv)
16 {
17 char buf[100];
18 ssize_t ret;
19 struct sigaction oldact;
20 struct sigaction act;
21
22 act.sa_handler = int_handler;
23 act.sa_flags=0;
24 act.sa_flags |= SA_RESTART;
25 sigemptyset(&act.sa_mask);
26 if (-1 == sigaction(SIGINT,&act,&oldact))
27 {
28 printf("sigaction failed!/n");
29 return -1;
30 }
31
32 bzero(buf,100);
33
34 ret = read(STDIN_FILENO,buf,10);
35 if (ret == -1)
36 {
37 printf ("read error %s/n", strerror(errn o));
38 }
39 printf ("read %d bytes, content is %s/n",ret,buf );
40 sleep (10);
41 return 0;
42 }
這裡我們就看第二種解決辦法SA—restart
運行看結果:
^Cint handler 2
^Cint handler 2
^Cint handler 2
^Cint handler 2
^Cint handler 2
^Cint handler 2
hgfd
read 5 bytes, content is hgfd
^Cint handler 2
在程式read之前不要輸入,ctrl+c這樣不會中斷read輸入後主程式就向下運行啦,這樣就不在低速的系統調用即read中啦,所以再次ctrl+c結束;
下面改程式:把程式24行注釋掉:結果
^Cint handler 2
read error Interrupted system call
read -1 bytes, content is
程式立即結束啦,
但我們和第一次相比也觀察到很奇怪的結果
根據結果
比較,其實是第二次運行是把ctrl+c讀入,而第一次就是運行啦訊號處理函數,不把ctrl+c作為READ的讀入,