本章簡單描述訊號。訊號是linux系統中,核心和程序通訊的一種方式。如果核心希望打斷程序的順序執行,那麼核心會在程序的pcb中記錄訊號。而當這個程序被分配到cpu,進入執行狀態時,首先會檢查是否有訊號,如果有訊號,那麼程序會先嘗試執行訊號處理函式。
核心需要打斷程序執行的時機:
int* p = null;
*p = 100;
// 此時**無法再繼續執行,核心會傳送sigse**訊號給程序,這是我們常見的段錯誤
int a = 0;
int b = 1/a;
// 除0操作,傳送sigfpe給程序
int main()
}執行該程式後,再按ctrl+c,結果是四個程序全部退出
int main()
}有了signal的處理之後,ctrl+c傳送的sigint不會導致程序退出。
通過kill -l
命令可以看到系統定義的訊號型別,訊號值小於32的是傳統的訊號,稱之為非實時訊號,而大於32的稱之為實時訊號。這裡只討論非實時訊號。
可以通過signal函式,註冊訊號處理函式。如果沒有註冊訊號處理函式,那麼按照預設方式處理。
也可以通過signal設定忽略訊號。
訊號預設處理動作
發出訊號的原因
sighup
a程序session leader退出時,同session的其他程序會收到這個訊號
sigint
actrl+c
sigquit
cctrl+d
sigill
c非法指令
sigabrt
c呼叫abort函式產生的訊號
sigfpe
c浮點異常
sigkill
aefkill訊號
sigse**
c無效的記憶體引用
sigpipe
a管道破裂: 寫乙個沒有讀埠的管道
sigalrm
a由alarm(2)發出的訊號
sigterm
a終止訊號
sigusr1
a使用者自定義訊號1
sigusr2
a使用者自定義訊號2
sigchld
b子程序狀態變化會給父程序傳送sigchld訊號
sigcont
程序繼續(曾被停止的程序)
sigstop
def暫停程序
sigtstp
d控制終端(tty)上按下停止鍵
sigttin
d後台程序企圖從控制終端讀
sigttou
d後台程序企圖從控制終端寫
a 預設的動作是終止程序
b 預設的動作是忽略此訊號
c 預設的動作是終止程序並進行核心映像轉儲(dump core)
d 預設的動作是停止程序
e 訊號不能**獲
f 訊號不能被忽略
因為sigkill不能**獲,那麼以下**是不正常
signal(sigkill, handle) //***x
#include #include #include void signal_handle(int a)
int main()
}
訊號值小於32的都是不可靠訊號,假如程序收到乙個訊號來不及處理,這時候又收到乙個同樣的訊號,那麼這兩個訊號會合併成乙個訊號,這個原因是因為程序儲存該訊號的值只有1位。
假如乙個程序呼叫了某系統呼叫導致該進行處於掛起狀態,而此時該程序接收到乙個訊號,那麼該系統呼叫被喚醒。通常該系統呼叫會返回-1,錯誤碼是eintr
。
也有些系統呼叫,可以設定打斷後重啟,這樣就不會被訊號打斷,具體參考man 7 signal
如果使用signal函式註冊訊號處理函式,預設被中斷的系統呼叫是自動重啟的。
// 阻塞
int ret = read(0, buf, sizeof(buf));
printf("read data\n");
#include #include #include void handle(int v)
int main()
訊號會導致可重入問題,比如乙個全域性鍊錶。
std::vectorv;
void handler(int sig)
int main()
}以上**在一定情況下會崩潰,在main函式中不停呼叫push_back,如果在push_back執行一半時,被中斷打斷,然後去執行中斷處理函式時,那麼該中斷處理函式的push_back會崩潰。
有些系統呼叫本身帶有區域性靜態變數,因此那些函式不能在訊號處理函式中呼叫,比如strtok
,readdir
等,對應的可重入的函式是strtok_r
,readdir_r
。
可以通過kill函式傳送訊號。
呼叫kill
傳送訊號
程序1核心
程序2
kill也可以程序組傳送訊號#include #include int main()
//掩蓋不可靠訊號
#include #include #include // 掩蓋sigint
// 掩蓋乙個可靠訊號
void handle(int v)
int main()
}
#include #include #include // 掩蓋34
// 掩蓋乙個可靠訊號
void handle(int v)
int main()
}
signal(sigpipe, sig_ign);
#include void handle(int v)
int main()
}
以上例子,忽略sigpipe訊號,那麼程序收到sigpipe後,不會有任何反應。
遮蔽和忽略不同,忽略意味著在忽略期間,接收的訊號就被忽略了。而遮蔽的意思,是暫時遮蔽,遮蔽期間收到的訊號依舊在,如果某一時刻該訊號不再忽略時,該訊號的處理程式會被呼叫。
設定遮蔽集合,使用sigprocmask
sigchld訊號產生於子程序退出和狀態變化,父程序通常在該訊號的處理函式中,呼叫wait來**子程序的pcb,這樣可以避免阻塞。
#include void chld_handle(int v)
}int main()
}
sigaction和signal一樣用來註冊訊號處理函式,siqqueue和kill一樣,用來傳送訊號,但是sigaction比signal功能強大,signal比較簡單。
強大:可以傳遞引數
可以獲得傳送訊號的程序資訊
可以設定sa_restart
#include #include #include //void handle(int v){}
//// 新的訊號處理函式
void handle(int v, siginfo_t* info, void* p)
int main()
#include #include #include char buf[1024];
void handle_data()
void handle_chld1(int v)
}void handle_chld(int v, siginfo_t* info, void* p)
int main()
// 如果是其他錯誤原因,就break
break;
}pid_t pid = fork();
if(pid == 0)
}}
#include #include void handle(int v, siginfo_t* info, void* p)
int main()
#include #include int main()
signal:註冊訊號處理函式
kill:傳送訊號
sigprocmask:設定訊號掩碼
sigemptyset:清空訊號集
sigfillset:設滿訊號集
sigaddset:往訊號集增加乙個訊號
sigdelset:從訊號集刪除乙個訊號
sigismember:判斷訊號否則在訊號集
sigaction:註冊更加強大的處理函式
sigqueue:傳送訊號
abort
alarm
pause
第六章 訊號 函式sleep
該函式用於讓呼叫程序掛起,直到 已經過了指定的時間,或者 呼叫程序捕捉到乙個訊號,並從訊號處理程式返回 include unsigned int sleep unsigned int seconds 返回值 若已經過了指定的時間,則返回0 若呼叫程序捕捉到乙個訊號,並從訊號處理程式返回,則sleep...
mysql第六章 第六章 mysql日誌
第六章 mysql日誌 一 錯誤日誌 錯誤日誌的預設存放路徑是 mysql 存放資料的地方 hostname.err 1.修改錯誤日誌存放路徑 mysqld log error data mysql mysql.log 2.檢視配置命令 show variables like log error 3...
第六章 指標
1.多位元組資料的位址是在最左邊還是最右邊的位置,不同的機器有不同的規定,這也正是大端和小端的區別,位址也要遵從邊界對齊 2.高階語言的乙個特性就是通過名字而不是位址來訪問記憶體的位置,但是硬體仍然通過位址訪問記憶體位置 3.記憶體中的變數都是義序列的0或1的位,他們可以被解釋為整數或者其他,這取決...