做淘寶網(wǎng)站java代碼站長工具seo綜合查詢分析
文章目錄
- 正文前的知識準(zhǔn)備
- kill 命令查看信號
- man手冊查看信號
- 信號的處理方法
- 認(rèn)識信號產(chǎn)生的5種方式
- 1. 工具
- 2. 鍵盤
- 3. 系統(tǒng)調(diào)用
- kill 向任意進(jìn)程發(fā)送任意信號
- raise 給調(diào)用方發(fā)送任意信號
- abort 給調(diào)用方發(fā)送SIGABRT信號
- 4. 軟件條件
- 5. 異常
正文前的知識準(zhǔn)備
kill 命令查看信號
在命令行終端輸入命令kill -l
快速查看信號列表
信號列表中的每一項(xiàng)都由【數(shù)字】和【名字】兩部分構(gòu)成,但是信號本質(zhì)上就只是一個(gè)【數(shù)字】而已,【名字】只是一個(gè)宏,如何證明,看源碼定義:
信號列表中一共有62個(gè)信號,沒有0、32、33號信號,信號可以分成實(shí)時(shí)信號(34 ~ 64)和非實(shí)時(shí)信號(1 ~ 31),后面談到的所有內(nèi)容只涉及非實(shí)時(shí)信號。
man手冊查看信號
kill -l
只是簡單羅列一下OS中有哪些信號而已,這種方式不足以了解到更多的知識,還有另外一種查看信號的方式——man 手冊。
man 7 signal
命令可用于查看 Linux 中有關(guān)信號的手冊頁。這個(gè)命令會顯示與信號相關(guān)的信息,其中包含了關(guān)于信號的詳細(xì)信息,如信號的編號、名稱、含義、默認(rèn)處理方式等,可以更好地理解信號的概念和用法。(文章后面的很多地方都會用到表里的內(nèi)容)
信號的處理方法
信號的完整生命周期通常分為3個(gè)階段:信號的產(chǎn)生、信號的保存、信號的處理。
本來信號的處理不是放在文章的內(nèi)容,但是為了更好的理解信號產(chǎn)生的現(xiàn)象,這里提前了解一下。
信號的處理方法有三種:
- 默認(rèn):man手冊中提到,OS為每個(gè)信號都設(shè)置了一個(gè)默認(rèn)行為,當(dāng)一個(gè)進(jìn)程收到信號時(shí)會執(zhí)行對應(yīng)的行為。
- 自定義捕捉:當(dāng)進(jìn)程收到一個(gè)信號,不執(zhí)行默認(rèn)行為轉(zhuǎn)而執(zhí)行程序員指定的行為,這個(gè)過程稱之為 “自定義捕捉”。
- 忽略:進(jìn)程收到信號之后什么都不做,即忽略該信號。
這里介紹一個(gè)能夠更改進(jìn)程信號處理方法的系統(tǒng)調(diào)用signal
。
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
說明:
- 使用該方法要包含頭文件
signal.h
。 sighandler_t
是一個(gè)函數(shù)指針,指向的函數(shù)參數(shù)個(gè)數(shù)為1,參數(shù)類型為int
,返回值類型為sighandler_t
。signum
是指某個(gè)信號,表示對該信號設(shè)置自定義處理方法。handler
是程序員對信號signum
的自定義處理方法。- 該方法的作用是將進(jìn)程收到信號
signum
的處理動作由默認(rèn)改為程序員自定義的handler
方法,即當(dāng)進(jìn)程收到信號signum
時(shí),不再執(zhí)行默認(rèn)的處理動作,轉(zhuǎn)而執(zhí)行程序員自定義的handler
方法來處理處理信號signum
。
注意:signal
被調(diào)用時(shí),handler
方法不會被立即執(zhí)行,而是進(jìn)程收到信號之后才會被執(zhí)行,如果沒有收到對應(yīng)的信號,handler
方法永遠(yuǎn)也不會執(zhí)行。
認(rèn)識信號產(chǎn)生的5種方式
1. 工具
第一種信號產(chǎn)生的手段就是Linux操作系統(tǒng)內(nèi)置的 kill 工具,通過該工具能夠做到向任意進(jìn)程發(fā)送任意信號。
LJH@hecs-66624:~$ ll /usr/bin/kill
-rwxr-xr-x 1 root root 30952 Sep 9 2021 /usr/bin/kill*
通常,kill
命令的使用形式是
kill -<信號編號> <進(jìn)程ID>
例如,輸入命令 kill -9 1234
,kill 工具會向 ID 為 1234 的進(jìn)程發(fā)送 SIGKILL 信號,SIGKILL 信號的默認(rèn)行為強(qiáng)制終止進(jìn)程。
再介紹一下2號信號 SIGINT,它的默認(rèn)處理動作的 Term(terminate,終止),即終止一個(gè)正在運(yùn)行的進(jìn)程。
這里就通過一個(gè)實(shí)現(xiàn)來驗(yàn)證一下kill
命令能否對一個(gè)進(jìn)程發(fā)送信號,同時(shí)還演示一下該如何使用系統(tǒng)調(diào)用signal
來設(shè)置進(jìn)程的信號處理方法。
實(shí)驗(yàn)內(nèi)容如下:
- 寫一個(gè)程序死循環(huán)向顯示器輸出 "I am working, my pid is " + 進(jìn)程 ID。
- 在 1 的基礎(chǔ)上,通過
kill
工具發(fā)送 2 號信號 SIGINT 來終止該進(jìn)程,驗(yàn)證進(jìn)程處理信號 SIGINT 的默認(rèn)動作。 - 在 1 的基礎(chǔ)上,先調(diào)用
signal
將進(jìn)程對信號 SIGINT 的處理動作設(shè)置為向顯示器輸出 "get a signal: " + 收到的信號的數(shù)字、然后退出,再進(jìn)程執(zhí)行過程中向該進(jìn)程發(fā)送信號 SIGINT,如果輸出 “get a signal: 2” 并退出,則說明猜測正確。 - 在 1 的基礎(chǔ)上,調(diào)用
signal
將進(jìn)程對信號SIGINT的處理動作設(shè)置為忽略,然后在進(jìn)程運(yùn)行過程中向該信號發(fā)送信號SIGINT,如果信號發(fā)送無效,則說明猜測正確。
實(shí)驗(yàn)第2步:
代碼:
// cpp
#include <iostream>
// system call
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;int main()
{while (true){cout << "I am working, my pid is " << getpid() << endl;sleep(2);}return 0;
}
運(yùn)行過程:
結(jié)論:驗(yàn)證成功,進(jìn)程處理信號SIGINT的默認(rèn)動作確實(shí)是終止。
實(shí)驗(yàn)第3步
代碼:
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;void handler(int signum)
{cout << "get a signal: " << signum << endl;exit(0);
}int main()
{signal(SIGINT, handler);while (true){cout << "I am working, my pid is " << getpid() << endl;sleep(2);}return 0;
}
運(yùn)行結(jié)果:
結(jié)論:驗(yàn)證成功,實(shí)現(xiàn)了對信號SIGINT的自定義捕捉。
實(shí)驗(yàn)第4步
SIG_IGN的定義:
#define SIG_IGN ((__sighandler_t) 1) /* Ignore signal. */
代碼:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;int main()
{signal(SIGINT, SIG_IGN);while (true){cout << "I am working, my pid is " << getpid() << endl;sleep(2);}return 0;
}
運(yùn)行結(jié)果
結(jié)論:驗(yàn)證成功,實(shí)現(xiàn)了對信號SIGINT的忽略操作。
2. 鍵盤
Ctrl+C
這個(gè)組合鍵是我們在Linux最常用的組合鍵之一,它能終止正在執(zhí)行過程中的進(jìn)程,就像下面這樣:
對于Ctrl+C
這個(gè)組合鍵,我們雖然會用,但是卻不怎么了解它的原理,既然這里提到了它,就說明它的原理和信號有關(guān),理由是我們輸入Ctrl+C
組合鍵被操作系統(tǒng)解析成SIGINT信號,然后發(fā)送給了正在運(yùn)行的進(jìn)程,SIGINT信號的默認(rèn)動作是終止進(jìn)程,所以死循環(huán)被終止了。
詳細(xì)的原理可以看一下個(gè)人寫的另外一篇文章《解析Linux鍵盤組合鍵產(chǎn)生信號的完整過程:從硬件中斷到信號發(fā)送》
憑什么這么說?接下來就要用一個(gè)實(shí)驗(yàn)來驗(yàn)證這個(gè)結(jié)論是否正確。
實(shí)驗(yàn)內(nèi)容如下:
寫一個(gè)程序,內(nèi)容是死循環(huán)向顯示器輸出 "I am working, my pid is " + 進(jìn)程ID,同時(shí)調(diào)用signal設(shè)置對信號SIGINT的捕捉方法為向顯示器輸出 "get a signal: " + 信號數(shù)字,但是不退出,進(jìn)程執(zhí)行過程中,不斷按下ctrl + c
,觀察實(shí)驗(yàn)現(xiàn)象,如果信號數(shù)字是2,就說明收到了信號SIGINT,結(jié)論正確。
代碼:
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;void handler(int signum)
{cout << "get a signal: " << signum << endl;// exit(0);
}int main()
{signal(SIGINT, handler);while (true){cout << "I am working, my pid is " << getpid() << endl;sleep(2);}return 0;
}
運(yùn)行結(jié)果:
這里能夠看到在進(jìn)程給執(zhí)行過程中,連續(xù)按下Ctrl+C
,自定義的handler
方法不斷被執(zhí)行,然后向屏幕輸出收到了2號信號,說明了上面的結(jié)論是正確的。
于此同時(shí),再分別看一下源碼中對信號SIGINT
的定義中的注釋和man手冊對SIGINT
的描述
#define SIGINT 2 /* Interactive attention signal. */Signal Standard Action Comment
────────────────────────────────────────────────────────────────────────
SIGINT P1990 Term Interrupt from keyboard
“Interactive Interrupt Signal”,交互式中斷信號,強(qiáng)調(diào)了它是通過用戶的交互操作觸發(fā)的,用于引起程序的注意并中斷執(zhí)行,而man手冊中 “Interrupt from keyboard” 的注釋表明,這個(gè)“交互操作”指的就是 Ctrl+C 這個(gè)組合鍵,Action 項(xiàng)為 Term 表示默認(rèn)行為是終止進(jìn)程。
3. 系統(tǒng)調(diào)用
在第2點(diǎn)時(shí)提到,shell程序通過系統(tǒng)調(diào)用來向目標(biāo)進(jìn)程發(fā)送信號,而系統(tǒng)調(diào)用就是產(chǎn)生信號的第3種方式,所以接下來說一下,都有哪些系統(tǒng)調(diào)用可以發(fā)送信號(說是系統(tǒng)調(diào)用,但其實(shí)這里只會講到一個(gè)系統(tǒng)調(diào)用,其余兩個(gè)都是C的庫函數(shù),不過它們兩個(gè)的底層都是封裝了系統(tǒng)調(diào)用,而且3者都是通過代碼的形式來實(shí)現(xiàn)信號發(fā)送,所以這里就一起介紹)。
kill 向任意進(jìn)程發(fā)送任意信號
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
kill 系統(tǒng)調(diào)用的功能是向指定的進(jìn)程發(fā)送指定的信號,參數(shù)pid
是目標(biāo)進(jìn)程ID,參數(shù)sig
是待發(fā)送信號,信號發(fā)送成功,返回值為0,信號發(fā)送失敗,返回值為-1,同時(shí)錯(cuò)誤碼(errno
)被設(shè)置。
理論部分完了,接下來是實(shí)驗(yàn)驗(yàn)證,到底 kill 系統(tǒng)調(diào)用能不能向一個(gè)進(jìn)程發(fā)送信號。
實(shí)驗(yàn)內(nèi)容:
使用 kill 系統(tǒng)調(diào)用簡單實(shí)現(xiàn)一個(gè)屬于自己的 kill
命令,即 mykill
,輸入 ./mykill -<信號編號> <進(jìn)程ID>
能夠做到和 kill
命令一樣的功能,然后啟動一個(gè)死循環(huán)輸出 "I am working, my pid is " + 進(jìn)程ID 的程序,在另一個(gè)窗口向該該進(jìn)程發(fā)送信號SIGKILL,如果死循環(huán)進(jìn)程 Killed,說明 kill 系統(tǒng)調(diào)用確實(shí)能夠向一個(gè)進(jìn)程發(fā)送信號。
代碼:
---------------./testsig-----------------------
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;int main()
{while (true){cout << "I am working, my pid is " << getpid() << endl;sleep(1);}return 0;
}---------------./mykill------------------------
#include <iostream>
#include <string>
#include <cstring>
#include <cerrno>
#include <signal.h>
#include <sys/types.h>using namespace std;// ./mykill -9 pid
int main(int argc, char* argv[])
{if (argc != 3){cout << "Usage: " << argv[0] << " -signumber pid" << endl;return 1;}int signumber = stoi(argv[1]+1);int pid = stoi(argv[2]);int n = kill(pid, signumber);if (n < 0){cout << "kill error, error message: " << strerror(errno) << endl;return 2;}return 0;
}
運(yùn)行結(jié)果:
raise 給調(diào)用方發(fā)送任意信號
#include <signal.h>
int raise(int sig);
raise 方法還有下面的 abort 方法嚴(yán)格上來說不算是系統(tǒng)調(diào)用,但都屬于調(diào)用函數(shù)發(fā)送信號的范疇,并且比較常見,這里也一起研究一下。raise 方法的作用是給調(diào)用 raise 的進(jìn)程發(fā)送一個(gè)指定的信號 sig,發(fā)送成功返回0,發(fā)送失敗返回一個(gè)非0整數(shù)。
使用演示:
寫一個(gè)程序,每秒向顯示器輸出 "I am working, my pid is " + 進(jìn)程ID,3秒后向自己發(fā)送信號SIGKILL。
代碼:
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;int main()
{int cnt = 0;while (true){if (cnt == 3) {cout << "raise: send SIGKILL to caller" << endl;raise(SIGKILL);}cout << "I am working, my pid is " << getpid() << endl;cnt++;sleep(1);}return 0;
}
運(yùn)行結(jié)果:
abort 給調(diào)用方發(fā)送SIGABRT信號
#include <stdlib.h>
void abort(void);
說明:
abort 方法會向調(diào)用該方法的進(jìn)程發(fā)送 SIGABRT 信號,SIGABRT 的全稱是 “Signal Abort”,“abort” 的中文意思是 “中止” 或 “放棄”,在計(jì)算機(jī)術(shù)語中指的是異常終止程序的行為,所以,進(jìn)程處理信號 SIGABRT 的默認(rèn)動作就是終止進(jìn)程。
代碼驗(yàn)證及使用演示:
#include <iostream>
#include <cstdlib>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;void handler(int signo)
{std::cout << "get a signo: " << signo << std::endl;exit(0);
}int main()
{signal(SIGABRT, handler);int cnt = 0;while (true){if (cnt == 3) {cout << "abort: send SIGABRT to caller" << endl;abort();}cout << "I am working, my pid is " << getpid() << endl;cnt++;sleep(1);}return 0;
}
運(yùn)行結(jié)果:
4. 軟件條件
產(chǎn)生信號的第4種方式就是【軟件條件】,相比起前三種,這個(gè)看起來就很抽象,個(gè)人是這樣理解的:在 “軟件條件產(chǎn)生信號” 中,“軟件” 指的是各種進(jìn)程或者程序。當(dāng)某個(gè)進(jìn)程滿足了某種條件,比如一個(gè)錯(cuò)誤的操作、一個(gè)特定的事件發(fā)生或者一個(gè)狀態(tài)的改變,它可能會向其他進(jìn)程、操作系統(tǒng)或者它自己發(fā)送一個(gè)信號,以通知它們發(fā)生了某個(gè)事件或者需要采取某種行動。
下面來講一個(gè)經(jīng)典的軟件條件的例子,13號 管道信號 SIGPIPE:
管道是進(jìn)程間通信的手段之一,管道本身是OS提供的基于文件系統(tǒng)實(shí)現(xiàn)的一段內(nèi)核級文件緩沖區(qū),進(jìn)程A先將數(shù)據(jù)寫入緩沖區(qū)中,進(jìn)程B來讀取這樣就實(shí)現(xiàn)了兩個(gè)進(jìn)程間的通信。
而一個(gè)管道只能支持單向通信,換言之,通信的進(jìn)程雙方得協(xié)商誰是管道的寫端,誰是管道的讀端,講這個(gè)有意義嗎,有意義,因?yàn)楣艿劳ㄐ胖幸?guī)定了這樣一種情況,當(dāng)管道的讀端進(jìn)程關(guān)閉了管道的讀端之后,OS會強(qiáng)制終止寫端進(jìn)程,因?yàn)楣艿罃?shù)據(jù)已經(jīng)沒人讀取了,再寫也已經(jīng)沒有意義。
上面是結(jié)論,中間的原理是這樣的,管道本身是OS提供用于進(jìn)程間通信的資源,OS內(nèi)部有通信需求的進(jìn)程肯定不止這兩個(gè),所以,OS內(nèi)肯定會創(chuàng)建很多的管道資源來 為進(jìn)程提供通信服務(wù),而OS作為計(jì)算機(jī)軟硬件資源的管理者,它內(nèi)部肯定會有一個(gè)描述管道信息的結(jié)構(gòu)體以及組織管理所有管道的數(shù)據(jù)結(jié)構(gòu),因此,當(dāng)某個(gè)管道的讀端進(jìn)程將管道的讀端關(guān)閉了,OS肯定就會知道并將描述管道信息的結(jié)構(gòu)體對象內(nèi)的信息做修改,當(dāng)該管道的寫端進(jìn)程嘗試寫入數(shù)據(jù)時(shí),OS會檢查管道的狀態(tài),如果發(fā)現(xiàn)該進(jìn)程滿足 “ 向不滿足寫入條件的管道進(jìn)行寫入 ” 的條件時(shí),OS就會向該進(jìn)程發(fā)送 SIGPIPE 信號,通知它寫入操作失敗,該進(jìn)程需要處理這個(gè)信號。
首先來看一下man手冊對于 SIGPIPE 信號的描述
Signal Standard Action Comment
────────────────────────────────────────────────────────────────────────
SIGPIPE P1990 Term Broken pipe: write to pipe with no readers; see pipe(7)
其次慣例操作實(shí)驗(yàn)驗(yàn)證,內(nèi)容如下:
pipe_server
進(jìn)程作為管道的讀端,從管道中讀取數(shù)據(jù)并輸出,讀端進(jìn)程會在運(yùn)行3秒后退出pipe_client
進(jìn)程作為管道的寫端,不停向管道寫入數(shù)據(jù),同時(shí)寫端進(jìn)程對SIGPIPE信號做自定義捕捉,看是否真的收到了SIGPIPE信號。
代碼如下:
---------------Command.hpp------------------------
#ifndef __COMMAND_HPP__
#define __COMMAND_HPP__#include <iostream>
#include <string>
#include <cerrno>
#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>using std::cerr;
using std::cin;
using std::cout;
using std::endl;
#define Mode 0666class Fifo
{
public:Fifo(const char *path) : _path(path){umask(0);int n = mkfifo(_path.c_str(), Mode);if (n == 0){cout << "mkfifo success" << endl;}else{cerr << "mkfifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;exit(1);}}~Fifo(){int n = unlink(_path.c_str());if (n == 0){cout << "remove fifo success" << endl;}else{cerr << "remove fifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;exit(1);}}protected:std::string _path;
};#endif
---------------PipeServer.cc------------------------
#include "Command.hpp"const char *path = "fifo";int main()
{// 創(chuàng)建管道Fifo fifo(path);// 獲取管道讀端int rfd = open("fifo", O_RDONLY);if (rfd >= 0){cout << "open fifo success" << endl;}else{cerr << "open fifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;exit(1);}// 讀數(shù)據(jù)char buffer[1024]{0};int cnt = 4;while (cnt--){ssize_t n = read(rfd, buffer, sizeof(buffer) - 1);if (n > 0){buffer[n] = 0;cout << "get msg from client: " << buffer << endl;}else if (n == 0){cout << "client quit, me too!" << endl;break;}else{cerr << "read from fifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;break;}}close(rfd);return 0;
}
---------------PipeClient.cc------------------------
#include "Command.hpp"void handler(int signum)
{cout << "get a signum: " << signum << endl;cout << "Pipe is broken, now I quit" << endl;exit(1);
}int main()
{signal(SIGPIPE, handler);// 獲取管道寫端int wfd = open("fifo", O_WRONLY);if (wfd >= 0){cout << "open fifo success" << endl;}else{cerr << "open fifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;exit(1);}// 發(fā)消息const char *inbuffer = "I am process A and I am client";while (true){ssize_t n = write(wfd, inbuffer, strlen(inbuffer));if (n < 0){cerr << "write to fifo failed, errno: " << errno << ", errmsg: " << strerror(errno) << endl;break;}sleep(1);}close(wfd);return 0;
}
運(yùn)行結(jié)果:
5. 異常
了解過進(jìn)程的都知道,一個(gè)進(jìn)程退出只會有以下3種場景:
- 代碼運(yùn)行完畢,結(jié)果正確。
- 代碼運(yùn)行完畢,結(jié)果不正確。
- 代碼運(yùn)行過程中,進(jìn)程異常終止。
而異常終止的本質(zhì)原因是因?yàn)檫M(jìn)程收到了信號,所以,第5種產(chǎn)生信號的方式就是異常。
舉兩個(gè)常見的代碼異常,進(jìn)程收到信號的例子:
- 代碼除零 8) SIGFPE
下面是一段演示代碼,里面寫了除零操作。
#include <iostream>
using namespace std;int main()
{int a = 10;a /= 0;return 0;
}
運(yùn)行結(jié)果:
運(yùn)行之后看到,程序輸出 “Floating point exception (core dumped)” 后就結(jié)束了,為了確認(rèn)其是否收到了信號,這里使用signal
設(shè)置自定義捕捉 SIGFPE 信號,代碼修改如下:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>using namespace std;void handler(int signum)
{cout << "get a signum: " << signum << endl;sleep(1);
}int main()
{signal(SIGFPE, handler);int a = 10;a /= 0;return 0;
}
輸出結(jié)果:
捕捉了之后,確實(shí)驗(yàn)證了進(jìn)程收到了 SIGFPE
信號,但同時(shí)也看到了一個(gè)很奇怪的現(xiàn)象,明明代碼里從頭到尾都沒有寫循環(huán),為什么handler
方法會被一直執(zhí)行?
理由:信號的處理方法從Core
退出被改成的向顯示器輸出一句話,這就導(dǎo)致了原本該退出的進(jìn)程沒有退出,進(jìn)程沒有退出,除零異常就一直存在,進(jìn)程在被CPU調(diào)度時(shí)就會一直觸發(fā)異常,OS會不斷地向進(jìn)程發(fā)送 SIGFPE 信號,進(jìn)程收到信號并處理就會一直向屏幕輸出,導(dǎo)致了一種死循環(huán)的局面。
- 野指針 11) SIGEGV
下面是一份演示代碼,里面寫了野指針訪問操作。
#include <iostream>
using namespace std;int main()
{int *p = nullptr;*p = 100;return 0;
}
運(yùn)行結(jié)果:
運(yùn)行之后看到,程序輸出 “Segmentation fault (core dumped)” 后直接退出,為了驗(yàn)證進(jìn)程是否真的收到了信號,設(shè)置自定義捕捉 SIGSEGV 信號,觀察是否收到信號,代碼修改如下:
#include <iostream>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
using namespace std;void handler(int signum)
{cout << "get a signum: " << signum << endl;sleep(1);
}int main()
{signal(SIGSEGV, handler);int *p = nullptr;*p = 100;return 0;
}
運(yùn)行結(jié)果: