程序通訊-訊號

night000day發表於2024-03-06

程序通訊-訊號

//本章學習控制linux程序訊號函式,實現透過訊號控制程序,使用訊號傳送資訊,學習相關訊號操作
//訊號操作:1.預設動作 2.改變動作 3.忽略訊號 4.阻塞/遮蔽訊號
//相關函式:kill/signal/sigqueue/sigaction/sigset_t相關函式/raise/alarm

相關概念

<sys/types.h>
<signal.h>
linux一共62個訊號
預設/預設

kill相關命令/函式

命令

//殺死'單個'程序
kill [option] <pid> [...]
//對'pid'程式傳送一個訊號
//一般前臺程式用ctrl+c終止;後臺程式用kill終止

//殺死所有'同名'程序
killall [option] <name> [...]
//對'程式名'程式傳送一個訊號

//殺掉一類程序/某個使用者的所有程序
pkill [OPTIONS] <PATTERN>
//pgrep + kill//pkill只需部分資訊
//kill/killall嚴謹,不完整則報錯
//與kill類似,pkill針對的是多個程序,kill針對單個程序

kill:常用命令
kill -sig pid//對'pid'程式傳送一個訊號
kill -l SIGKILL//列出SIGKILL的數值
kill -l//列出所有可用訊號
kill 0//終止所有由當前shell啟動的程序

killall:常用命令
killall -9 mysql//結束所有mysql程序

pkill:常用命令
pkill -f httpd//查詢httpd名的程式,並殺死
pkill -u fghfgh//殺死fgh使用者的所有程序//會導致fgh使用者退出

函式

<sys/type.h><signal.h>
int kill(pid_t pid,int sig)
//向pid程式傳送一個sig

pid//程序識別符號//>0 / 0 / -1 / <-1
->  >0:訊號發給'pid標誌的程式'(常用)
->  0:訊號發給呼叫程序的'同一組程式'
->  -1:訊號發給所有呼叫程序'有權傳送的程序'
->  <-1:訊號發給'-pid標誌的程式'

sig//準備傳送訊號程式碼
常用訊號:
-1 SIGHUP 過載
-2 SIGINT 中斷 ctrl+c
-3 SIGQUIT 退出 ctrl+\
-9 SIGKILL 殺死程序
-19 SIGSTOP 暫停程序
-18 SIGCONT 繼續程序
-14 SIGALRM alarm自動執行訊號

signal函式

void (*signal(int sig,void (*func)(int)))(int)
//void (signal)(int)//函式結構
//(int sig,void(
func)(int))//函式引數

小知識:不帶變數的引數
一般是需要輸入,但不使用的函式
工作中,先定介面,再寫程式碼//介面需要穩定,以後可能修改
如果定義了名稱不使用,編譯會警告//所有用純型別
//(int)//(int = 2)

用途:

  1. 改變訊號響應//設定執行函式,使用signal關聯訊號和函式
  2. 忽略某個訊號//signal(sig,SIG_IGN)//ignore
  3. 恢復預設動作//signal(sig,SIG_DFL)//default
//改變訊號響應
//定義訊號效果
void fun(int sig){
    printf("hello,world\n");
}
//接收SIGNINT訊號//執行fun()
signal(SIGINT,fun);

注意事項:
-9/-19 優先順序高於使用者定義內容/不可修改

sigqueue/sigaction函式

//為了讓訊號攜帶資訊

int sigqueue(pid_t pid,int sig,const union sigval value)
//kill 升級版本//傳送攜帶額外資料

int sigaction(int signum,const struct sigaction *act,struct sigaction *oldact)
//signal的升級版//接收額外資料
//act使用資料//oldact備份資料(上一個資料)

//use//sigaction
void fun(int sig, siginfo_t *info, void *arg){
    printf("sig:%d data:%d\n",sig,info->si_int);
}

struct sigaction m_action;
m_action.sa_handler=fun;
m_action.sa_flags=0;
sigacton(sig,)
//相關引數

//sigqueue///const union sigval value
union sigval{
    int sival_int;//儲存傳送整數
    void *sival_ptr;//儲存傳送地址
};

//sigaction//const struct sigaction *act
struct sigaction {
   void     (*sa_handler)(int);//存放執行函式//相容signal
   void     (*sa_sigaction)(int, siginfo_t *, void *);//與sigaction配合使用
   sigset_t sa_mask;
   int      sa_flags;//0->與以前signal相容//1->與現在sigqueue配合使用
   void     (*sa_restorer)(void);
};


//siginfo_t
The siginfo_t argument to sa_sigaction is a struct with the following fields:

siginfo_t {
   int      si_signo;     /* Signal number 訊號編號 */
   int      si_errno;     /* An errno value 如果為非零值則錯誤程式碼與之關聯 */
   int      si_code;      /* Signal code 說明程序如何接收訊號以及從何處收到*/
   int      si_trapno;    /* Trap number that caused
                             hardware-generated signal
                             (unused on most architectures) */
   pid_t    si_pid;       /* Sending process ID適用於SIGCHLD,代表被終止程序的PID  */
   uid_t    si_uid;       /* Real user ID of sending process適用於SIGCHLD,代表被終止程序所擁有程序的UID  */
   int      si_status;    /* Exit value or signal 適用於SIGCHLD,代表被終止程序的狀態 */
   clock_t  si_utime;     /* User time consumed 適用於SIGCHLD,代表被終止程序所消耗的使用者時間 */
   clock_t  si_stime;     /* System time consumed 適用於SIGCHLD,代表被終止程序所消耗系統的時間 */
   ==================
   sigval_t si_value;     /* Signal value */
   ==================
   int      si_int;       /* POSIX.1b signal */
   void    *si_ptr;       /* POSIX.1b signal */
   int      si_overrun;   /* Timer overrun count;
                             POSIX.1b timers */
   int      si_timerid;   /* Timer ID; POSIX.1b timers */
   void    *si_addr;      /* Memory location which caused fault */
   long     si_band;      /* Band event (was int in
                             glibc 2.3.2 and earlier) */
   int      si_fd;        /* File descriptor */
   short    si_addr_lsb;  /* Least significant bit of address
                             (since Linux 2.6.32) */
   void    *si_call_addr; /* Address of system call instruction
                             (since Linux 3.5) */
   int      si_syscall;   /* Number of attempted system call
                             (since Linux 3.5) */
   unsigned int si_arch;  /* Architecture of attempted system call
                             (since Linux 3.5) */
}

等待訊號 pause()函式

int pause(void)
//阻塞等待,直到收到一個訊號,往下執行

阻塞/遮蔽訊號 sigset_t型別使用

sigset_t型別的變數(本質上是一個陣列/存放多個訊號)->linux又稱:訊號阻塞原始碼集
int sigemptyset(sigset_t *set); //清空集合
int sigfillset(sigset_t *set); //加62個//把linux中62個訊號一起新增到set集合中
int sigaddset(sigset_t *set, int signum); //加一個//把signum訊號新增到set集合中
int sigdelset(sigset_t *set, int signum); //把signum訊號從集合中剔除
int sigismember(const sigset_t *set, int signum); //判斷signum在不在set

//設定訊號阻塞
int sigprocmask(int how, const sigset_t *set,sigset_t *oset)
how -> //怎麼使用//控制
SIG_BLOCK //設定訊號阻塞,把set和oset兩個集合中的所有訊號都阻塞
SIG_SETMASK //設定訊號阻塞,只阻塞set這個集合中的所有訊號
SIG_UNBLOCK //解除訊號阻塞
set ->//使用集合//儲存你想要阻塞的所有訊號
oset ->//備份集合//儲存之前你設定的阻塞訊號

//例:
sigset_t m_set,old_set;//定義訊號變數集合
sigemptyset(&m_set);//清空
sigaddset(&m_set,SIGINT)//加入訊號,SIGINT
sigaddset(&m_set,SIGQUIT)//加入訊號,SIGQUIT
sigprocmask(SIG_BLOCK,&m_set,&old_set)//對m_set和old_set內的訊號進行訊號阻塞
//old_set//之前設定的訊號遮蔽集合

現象:
kill -SIGINT PID//沒反應(被遮蔽了),還在等待訊號
if//kill -4 PID//反映了,退出
if//sigprocmask(SIG_UNBLOCK,&m_set,&old_set)
//反應,退出//被遮蔽訊號進來了,退出程序

其他訊號函式

//自己給自己訊號
int raise(int sig)
//等價於kill(getpid(),int sig)

//定時器,間隔多少秒,傳送SIGALRM訊號
unsigned alarm(unsigned seconds)
//比sleep()好//期間可以執行別的,sleep()只能傻等

例:
signal(SIGALRM,fun);
alarm(5);//間隔5秒鐘,alarm自動傳送SIGALRM訊號
pause();

void fun(int sig){
    printf("alarm使用了\n");
}

相關文章