天天看點

LinuxC信号-程序間通信方式之一

1.信号特性:
  簡單但不可靠,不能攜帶大量資訊,特定條件才觸發。
  包括軟體中斷和硬體中斷。
    軟體中斷如:調用abort、raise,alarm,setitimer等函數觸發的中斷
    硬體中斷如:除0導緻的SIGFPE(浮點數例外),非法通路内容導緻的SIGSEGV(段錯誤),非法内容對齊等導緻的總線錯誤(SIGBUS) 等等

2.信号三要素:
  1)編号:信号編号範圍是1~64。1~31為正常信号編号。34-64為實時信号。
  2)事件:同時每個編号對應一個觸發事件。如1->SIGHUP,2->SIGINT,3->SIGQUIT,... man 7 signal 可檢視全部信号。
       常見對應事件:Ctr+c 産生SIGINT(2),Ctrl+\ 産生SIGQUIT(3),Ctrl+z 産生SIGTSTP(20),
       除0操作 産生SIGFPE(8)浮點數例外,非法通路記憶體 産生SIGSEGV(11)段錯誤,非法記憶體對齊等 産生SIGBUS(7)總線錯誤
  3)預設動作:包括 Term終止程序,Ign忽悠,Core終止程序并生成Core檔案,Stop暫停程序,Cont繼續進行。
        注意:SIGKILL(9)和SIGSTOP(19)信号不允許被屏蔽、忽略、捕捉等,隻能執行預設動作。SIGKILL預設終止程序,SIGSTOP預設暫停程序。

3.常見信号産生函數
  kill(pid,sig)函數:發送sig信号。pid>0給指定程序 發送sig信号,pid=0給同組程序 發送sig信号,pid<-1給指定程序組 發送sig信号,pid=-1給所有程序 發送sig信号。
  raise(sig)   函數:給目前程序發送sig信号。
  abort()      函數:給目前程序發送SIGABRT信号。
  alarm(sec)   函數:sec大于0時表示sec秒後給目前程序發送SIGALRM信号。sec=0表示取消定時器。每個程序隻有唯一一個定時器。
  setitimer()  函數:周期定時器,which可選:ITIMER_REAL(自然定時,産生SIGALRM信号)、ITIMER_VIRTUAL(虛拟使用者空間計時,産生SIGVTALRM信号)、ITIMER_PROF(運作時計時,産生SIGPROF信号)
          
4.信号集
  未決信号集:産生了但還沒決定處理的待處理信号集合。未決就是沒決定的意思嘛。
  阻塞信号集:一般稱為信号屏蔽字mask。用來告訴核心屏蔽哪些信号,也就是說告訴核心哪些信号屏蔽掉不處理。
  核心是通過讀取未決信号集來判斷信号是否應該被處理的,信号屏蔽字mask可以影響未決信号集合。我們可以通過程式修改mask的值達到屏蔽指定信号的目的。
  簡單了解:就是所有未處理的信号,經過信号屏蔽字篩選後,剩下的就是未決信号集.

5.常見信号集操作函數
  sigset_t:信号集類型,是一個unsigned long類型。沒錯,是一個基本資料類型,但表示一個信号集合,說明是按位操作。
  sigemptyset(sigset_t *set)    函數:将set集合按位清空為0
  sigfillset(sigset_t *set)     函數:将set集合按位填充為1
  sigaddset(sigset_t *set,signum)  函數:将signum信号添加到set集合
  sigdelset(sigset_t *set,signum)  函數:将signum信号從set集合删除
  sigismember(sigset_t,signum)   函數:判斷signum信号是否在set集合裡
    注意:sigaddset()、sigdelset()、sigismember()等函數調用之前必須先調用sigemptyset()或者sigfillset()函數初始化信号集。
  sigprocmask(int how,sigset_t *set,sigset_t *oldset)    函數:用來屏蔽、解除屏蔽某個信号,本質是讀取并修改PCB(在程序核心裡)裡的信号屏蔽字mask。
    how:為SIG_BLOCK時,set表示需要屏蔽的信号,相當于mask=mask|set,"或"操作
       為SIG_UNBLOCK時,set表示需要解除的信号,相當于mask=mask&~set,"取反"後再"與"操作
       為SIG_SETMASK時,set表示用于替換之前的信号屏蔽字,相當于mask=set,set成為新的信号屏蔽字。
    set:傳入參數,需要操作的信号集
    oldset:傳出參數,傳回之前的信号集額,一般用于恢複時使用。
  sigpending(sigset_t *set):    函數:讀取目前程序的未決信号集,set為傳出參數。
  pause()  函數:主動挂起,處于阻塞狀态,等等任一信号送達喚醒,該信号不能是被屏蔽的,不然沒法送達呀。
  sigsuspend  函數:挂起等待信号。類似于pause函數,但pause有時序問題,可以使用sigsuspend函數解決時序問題。
  sigqueue  函數:對應kill函數,信号傳參,攜帶union參數。傳遞指針的話,本程序内才有意義。因為每個程序都有自己獨立的空間,程序間傳遞指針是沒有意義的。
  
6.信号捕捉函數
  signal(signum,handler)函數:
    捕捉指定的signum信号,觸發回調handler函數。handler是一個函數指針。由于曆史原因,相容性較差,很少使用。
  sigaction(signum,struct sigaction *act,struct sigaction *oldact)函數
    捕捉指定的signum信号,回調函數再act結構體裡。act為傳入參數,新的處理方式。oldact為傳出參數,傳回舊的處理方式,一般用于之前恢複處理方式時使用。
    struct sigaction{
      void (*sa_handler)(int);//信号捕捉後的處理函數,也可以指定為SIG_IGN表示忽悠,SIG_DEL表示預設處理方式
      void (*sa_sigaction)(int,siginfo_t*,void*);//sa_flags指定為SA_SIGINFO時信号捕捉後改為調用該函數,不調用sa_handler函數
      sigset_t sa_mask;//處理函數執行期間(可能執行很長時間呀)的信号屏蔽字,表示處理函數執行期間屏蔽哪些信号
      int sa_flags;//特定辨別位,通常為0表示預設屬性
      void (*sa_restorer)(void);//已過時,已棄用
    }
    處理函數執行期間,屏蔽字由sa_mask指定,預設情況下處理函數執行期間,被捕捉信号自動屏蔽,正常信号不支援排隊,多次産生同一信号可能隻産生一次觸發

7.SIGCHLD信号
  子程序終止時,或者子程序收到SIGSTOP信号暫停時,或者子程序收到SIGCONT信号後繼續運作時,都會發送該信号。