(已轉)Linux基礎第六章 訊號

2021-10-09 13:32:01 字數 4525 閱讀 6024

本章簡單描述訊號。訊號是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會崩潰。

有些系統呼叫本身帶有區域性靜態變數,因此那些函式不能在訊號處理函式中呼叫,比如strtokreaddir等,對應的可重入的函式是strtok_rreaddir_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的位,他們可以被解釋為整數或者其他,這取決...