(1)終端按鍵產生信號(與終端交互的進程)
Ctrl + c? → 2) SIGINT(終止/中斷)????? "INT" ----Interrupt
Ctrl + z? → 20) SIGTSTP(暫停/停止)? "T" ----Terminal 終端? 此時進程處于后臺運行
Ctrl + \? → 3) SIGQUIT(退出)????
(2)硬件異常產生信號
除0操作?? → 8) SIGFPE (浮點數例外)? ? "F" -----float 浮點數。
非法訪問內存? → 11) SIGSEGV (段錯誤)
總線錯誤? → 7) SIGBUS(內存未對齊)
(3)kill函數/命令產生信號
注意:kill函數或命令產生信號并不一定是要殺死進程,信號的含義是根據編號(或宏)來決定的,不是kill本身的含義。
kill命令向指定進程發送指定信號: kill –SIGKILL pid? // 終止該進程,向該進程發送9號信號???
kill函數向指定進程發送指定信號:
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
作用:向指定進程(pid)發送指定信號(sig),指定信號最好用宏表示,不用編號,因為在不同類型的操作系統中,信號的編號可能會不一樣,用宏表示可以增強移植性。
返回值:成功0,失敗-1(ID非法;信號非法;普通用戶殺init進程等權級問題,即權限不夠)。
pid > 0:發送信號給指定的進程。
pid = 0:發送信號給與調用kill函數進程屬于同一進程組的所有進程(包括本身)。
pid < 0:取|pid|發給對應進程組。
pid = -1:發送給進程有權限發送的系統中所有進程(包括本身)。
進程組:每個進程都屬于一個進程組,進程組是一個或多個進程集合,他們相互關聯,共同完成一個實體任務,每個進程組都有一個進程組長,默認進程組ID與進程組長ID相同。
權限保護:super用戶(root)可以發送信號給任意用戶,普通用戶是不能向系統用戶發送信號的。同樣,普通用戶也不能向其他普通用戶發送信號,終止其進程。 只能向自己創建的進程發送信號。普通用戶基本規則是:發送者實際或有效用戶ID == 接收者實際或有效用戶ID
(4)raise和abort函數(系統調用產生,包括上面的kill函數)
raise函數:給當前進程發送指定信號(自己給自己發),則有:raise(signo) == kill(getpid(), signo);
#include <signal.h>
int raise(int sig); ??成功:0,失敗非0值
?
abort 函數:給自己發送異常終止信號 6) SIGABRT 信號,終止并產生core文件
#include <stdlib.h>
void abort(void);
(5)alarm、setitimer函數(軟件條件產生)
設置定時器(鬧鐘)。在指定seconds后,內核會給當前進程發送14)SIGALRM信號。進程收到該信號,默認動作終止(結束進程)。每個進程都有且只有唯一個定時器。
#include <unistd.h>
unsigned int alarm(unsigned int seconds);成功:返回舊鬧鐘剩余的秒數,即該進程上一次調用alarm函數后還剩下的秒數;或者返回0(第一次調用alarm函數的時候)。無失敗。
注意:alarm(0)表示取消鬧鐘,不是說0秒后終止進程,是取消鬧鐘。另外:定時與進程狀態無關(自然時間),就緒、運行、掛起(阻塞、暫停)、終止、僵尸等,無論進程處于何種狀態,alarm都計時。
例:alarm(5) → 3sec → alarm(4) → 5sec → alarm(5) →0sec→ alarm(0)
alarm(5)返回0?? alarm(4)返回2??? alarm(5)返回0?? 緊隨著馬上的alarm(0)返回5,并且取消鬧鐘。
time命令。 time ./zsx 查看程序zsx執行的時間,時間由三部分組成:程序在進程系統空間運行的時間+用戶空間的時間+等待的時間(等待CPU、各種硬件資源等)=程序實際執行的時間。程序運行的瓶頸在于IO,優化程序,首選優化IO。
?
//練習:編寫程序,測試你使用的計算機1秒鐘能數多少個數。
#include <stdio.h>
#include <unistd.h>int main(void)
{int i;alarm(1);for(i = 0; ; i++)printf("%d\n", i);return 0;
}
#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
作用:類似alarm函數,有四點不一樣:1.setitimer函數對時間的計算方式有三種,用which參數指定,而alarm函數只有一種(自然時間);2. setitimer函數可以進行周期定時,即等待it_value時間后執行某一動作(收到信號),以后每隔it_interval時間再執行這一動作。而alarm函數只能實現等待it_value時間后執行某一動作(收到信號);3. setitimer函數可以精確到us級別,即其時間為tv_sec與tv_usec之和;4.返回值不一樣。
返回值:成功0;失敗-1,設置errno
參數which指定定時方式:1.自然定時:ITIMER_REAL → 14)SIGALRM 計算自然時間;2.虛擬空間計時(用戶空間):ITIMER_VIRTUAL → 26)SIGVTALRM? ?? ?只計算進程占用cpu的時間;3.運行時計時(用戶+內核):ITIMER_PROF → 27)SIGPROF ?計算占用cpu及執行系統調用的時間(即相對于自然時間,不包括等待時間)。
參數new_value為傳入參數,指定計時的大小,與alarm的參數作用一樣;
參數old_value為傳出參數,指定就舊鬧鐘剩余的秒數,作用類似alarm的返回值;結構體詳細描述如下:
struct itimerval {
struct timeval it_interval; /* next value */?? 下一次定時的值(間隔時間)
??? struct timeval it_value;??? /* current value */? 當前定時的值
};?? ??// it_interval或it_value設置為0表示清零操作,即取消定時。
struct timeval {
time_t???? ??tv_sec;???????? /* seconds */??? s
??? suseconds_t? ?tv_usec;??????? /* microseconds */? us
};
注意:每個進程都有且只有唯一個定時器。setitimer函數和alarm函數共用同一個定時器(鬧鐘)。
?
//練習: 使用setitimer函數實現alarm函數,重復計算機1秒數數程序。???
#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>unsigned int my_alarm(unsigned int sec) //實現alarm函數
{struct itimerval it, oldit;int ret;it.it_value.tv_sec = sec;it.it_value.tv_usec = 0;it.it_interval.tv_sec = 0;it.it_interval.tv_usec = 0;ret = setitimer(ITIMER_REAL, &it, &oldit);if (ret == -1) {perror("setitimer");exit(1);}return oldit.it_value.tv_sec;
}int main(void)
{int i;my_alarm(1); //alarm(sec);for(i = 0; ; i++)printf("%d\n", i);return 0;
}
//拓展練習:測試it_interval、it_value這兩個參數的作用。
#include <stdio.h>
#include <sys/time.h>
#include <signal.h>void myfunc(int signo)
{printf("hello world\n");
}int main(void)
{struct itimerval it, oldit;signal(SIGALRM, myfunc); //注冊SIGALRM信號的捕捉用戶處理函數,signal函數用于對信號進行注冊,真正捕捉該信號的是內核,內核捕捉該信號后就會去調用signal注冊時對應的用戶處理函數。 信號捕捉函數signal是一個典型的回調函數it.it_value.tv_sec = 5;it.it_value.tv_usec = 0;it.it_interval.tv_sec = 3;it.it_interval.tv_usec = 0;if(setitimer(ITIMER_REAL, &it, &oldit) == -1){perror("setitimer error");return -1;}while(1);return 0;
}
[root@localhost 01_signal_test]# ./setitimer1
hello world??? //等5s
hello world?? ?//等3s
hello world??? //等3s
hello world?? ?//等3s