linux--進程信號

一、信號

1.信號的定義


是linux系統爲了響應某些狀況而產生的事件。進程收到信號後應該採取相應的措施

2. 哪些情況會引發信號?


1.鍵盤事件,如ctrl+ c ,ctrl+/(結束程序)
2.非法內存
3.硬件故障
4.環境切換

3.如何查看信號


通過指令kill -l查看
這裏寫圖片描述

4.信號的默認處理方式


man 7 signal查看
這裏寫圖片描述

5.常用信號解釋


SIGINT ctrl+c發出的信號
SIGOUIT ctrl+\發出的信號
SIGUSER1 用戶自定義信號,常用於發送與獲取
SIGALRM 鬧鐘信號,用於倒計時
SIGPWR 關機,默認動作爲終止進程
SIGSTOP 停止進程的執行,默認作爲暫停處理
SIGKILL 無條件終止進程
SIGBUS 非法訪問內存地址,默認爲終止進程併產生core文件
SIGHUP 用戶退出shell,默認終止進程
SIGSEGV 進程進行了無效的內存訪問 ,默認動作爲終止進程
SIGPIPE 向一個沒有讀端的管道寫數據
SIGTERM 請求終止進程,kill命令缺省發送
SIGIO 此信號向進程指示發出一個異步IO事件
SIGWINCH 窗口大小改變時發出
SIGXCPU CPU時間限制超時
SIGXFSZ 進程超過文件大小限制
SIGTRAP 實現相關硬件異常
SIGILL 非法指令異常
SIGFPE 數學相關的異常,如被0除
SIGABRT 由調用abrot函數產生,進程非正常退出

6.進程收到信號的3種處理


1.默認:執行該信號的默認處理動作
2.忽略:信號來了不處理,丟掉信號SIGKILL SIGSTOP不可忽視
3.捕獲並處理:信號來了。執行自己寫的代碼, SIGKILL SIGSTOP不能捕獲

7.信號的分類


a.不可靠信號( 1-31不可靠):
linux的信號繼承自早期的Unix信號,
Unix信號的缺陷:
1.信號處理函數執行完畢,信號恢復成默認處理方式(linux已改進)
2.會出現信號丟失,信號不排隊
b.可靠信號 ( 34-64信號):
不會出現信號丟失,支持排隊,信號處理函數執行完畢,不會恢復成缺省處理方式。
c.實時信號:就是可靠信號
d.非實時信號:就是不可靠信號

二、操作信號

1.註冊信號


(1)signal函數


函數原型:typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

函數參數解釋
signum:指明瞭所要處理的信號的類型,可取除SIGKILL與SIGSTOP外的任一種信號
sighandler_t handeler:信號執行函數,可取三種方式獲得:
(1)自己定義函數
(2)SIG_IGN #define SIG_IGN ((sighandler_t)1) //忽略該信號
(3)SIG_DFL #define SIG_IGN ((sighandler_t)0) //默認處理

返回值:成功時返回信號處理函數指針
失敗時返回SIG_ERR
SIG_ERR #define SIG_IGN((sighandler_t)(-1))

(2)代碼實現:


1 
  2 #include <stdio.h>
  3 #include <signal.h>
  4 #include <unistd.h>
  5 #include <stdlib.h>
  6 
  7 void handler(int s)
  8 {
  9     printf("game over!\n");
 10     exit(0);
 11 }
 12 
 13 int main()
 14 {
 15     //ctrl+c
 16     signal(SIGINT,SIG_IGN);
 17     //crl+\信號
 18     signal(SIGQUIT,handler);
 19 
 20     for(;;)
 21     {
 22         printf("living!\n");
 23         sleep(1);
 24     }
 25 }
 26 

這裏寫圖片描述

2.如何給某一進程發送信號


方式1:


kill -信號值 pid

方式2:


函數:
int kill(int pid,int signum)
返回值:成功返回0,失敗返回-1
參數解釋:
signum:信號值,及信號編號
pid:進程id,如下值:

    pid>0 ,發送給pid進程
    pid=0;調用者所在的進程組的任何一個進程
    pid=-1;有權發送的任何一個進程,除了1;

進程組:進程組有若干個進程
用管道連接的進程,fork創建出來的父子進程屬於同一個進程組

後臺進程:jobs 查看
fg %id 將後臺進程調到前臺(id是作業號,非進程號)
ctrl+c 只發給前臺進程
前臺進程:ctrl+z 前臺轉後臺
直接以後臺方式啓動進程,(./a.out &)>a

代碼實現:


  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <unistd.h>
  4 #include <signal.h>
  5 
  6 void handler(int n)
  7 {
  8     printf("收到!\n");
  9 } 
 10 
 11 int main( void )
 12 {
 13     signal(SIGUSR1, handler);//用戶自定義信號
 14     pid_t pid = fork();//創建子進程
 15     if (pid == 0 ) {
 16         sleep(1);
 17         kill(getppid(), SIGUSR1);
 18         exit(0);
 19     } else {
 20         while ( 1 ) { 
 21             printf("^_^\n");
 22             sleep(3);
 23         }
 24     }
 25     return 0;
 26 }

結果:
這裏寫圖片描述

3.三個發送信號函數


給自己發信號: int rasie(int signum)
給進程組發送信號: int killpg(int pgrp,int sig)
暫停進程,直到信號被打斷 int pause(void)

三、SIGALRM信號


1.alarm函數


int alarmint sec)
當sec規定的時間到了,觸發SIGALRM信號,如果sec是0,表示清除信號
alarm(0)清除鬧鐘

返回值:若調用此函數前,進程已經設置了鬧鐘時間,則返回上一個鬧鐘時間的剩餘時間,否則返回0,失敗返回-1

2.代碼實現:


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>

void handler(int s) {
    printf("超時\n");
    exit(1);
}

int main( void )
{
    char buf[100] = {};
    printf("name:");

    signal(SIGALRM, handler);

    alarm(3);
    scanf("%s", buf);
    alarm(0); // 清除鬧鐘


    printf("name=%s\n", buf);

    for ( ; ; ) {
        printf("OK\n");
        fflush(stdout);
        sleep(1);
    }
}

j結果:
這裏寫圖片描述

四:簡單的考試計時


  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 #include <signal.h>
  4 #include <unistd.h>
  5 
  6 int X = 0;//錯誤數
  7 int V = 0;// 正確數
  8 
  9 void handler(int s) {
 10     printf("時間到\n");
 11     printf("V=%d, X=%d\n", V, X);
 12     exit(1);
 13 }
 14 
 15 int main( void )
 16 {
 17     signal(SIGALRM, handler);
 18     int i=0;
 19     alarm(20);
 20     srand(getpid());
 21     for ( i=0; i<10; i++) {
 22         int left = rand()%10;
 23         int right = rand()%10;
 24         printf("%d+%d=", left, right);
 25         int ret;
 26         scanf("%d", &ret);
 27         if ( left + right == ret ) {
 28             V++;

 29         } else {
 30             X++;
 31         }
 32     }
 33 
 34     printf("finish!\n");
 35     printf("V=%d, X=%d\n", V, X);
 36 }
 37 
 38 

結果:
這裏寫圖片描述

good night!

發佈了128 篇原創文章 · 獲贊 51 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章