程序通訊-訊號
//本章學習控制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)
用途:
- 改變訊號響應//設定執行函式,使用signal關聯訊號和函式
- 忽略某個訊號//signal(sig,SIG_IGN)//ignore
- 恢復預設動作//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");
}