国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

【Linux】進程信號之信號的產生

這篇具有很好參考價值的文章主要介紹了【Linux】進程信號之信號的產生。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

一、信號入門


什么是信號:信號就是一條消息,它用來通知進程系統(tǒng)中發(fā)生了一個某種類型的事件。

信號是多種多樣的,并且一個信號對應一個事件,這樣才能知道收到一個信號后,到底是一個什么事件,應該如何處理這個信號。

1、信號的一些特性

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

  1. 進程在沒有收到信號時就已經知道了一個信號應該怎么被處理了,這說明進程能夠識別并處理信號。
  2. 信號對于進程來說是隨時都有可能產生的,因此進程與信號是異步的!
  3. 由于進程與信號是異步的,當信號產生時,進程可能正在執(zhí)行優(yōu)先級更高的事情,這時進程并不能立即處理信號,需要在合適的時候再進行處理,因此在這個空窗期內信號要能夠被保存起來,這說明進程具有記錄信號的能力!
  4. 進程記錄的信號可能有很多個,因此進程需要用一種數據結構去管理所有的信號,在Linux下對于信號的管理采用的是位圖結構,比特位的位置代表信號的編號。
  5. 所以所謂的發(fā)送信號本質就是:直接修改特定進程的信號位圖中的特定的比特位。(由0 -> 1
  6. 進程信號的位圖結構本質還是屬于task_struct里面的數據,因此對于進程信號的位圖結構里面的數據的修改,只能有操作系統(tǒng)來完成,即無論有多少種信號產生的方式,最終都必須讓OS來完成最后的發(fā)送過程!

2、信號的處理方式

  1. 執(zhí)行默認動作(即操作系統(tǒng)給信號設定的默認動作)
  2. 忽略信號
  3. 執(zhí)行自定義動作(用戶修改了操作系統(tǒng)設定的默認動作,改成了自己想要的動作),操作系統(tǒng)為我們提供一個信號處理函數signal,可以要求內核在處理該信號時切換到用戶態(tài)執(zhí)行這個處理函數,這種方式稱為捕捉(Catch) 一個信號。

信號捕捉初識

信號捕捉主要是使用signal函數,該函數內部使用了回調函數。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器
該函數的作用就是將指定的信號的默認行為更改為執(zhí)行第二個參數對應的函數,這個函數要求必須是返回值為void參數是int的函數。

  • 參數
    1. 信號的編號。
    2. 回調函數的函數指針。
  • 返回值: 返回先前的信號處理函數指針,如果有錯誤則返回SIG_ERR(-1)

實例代碼:
我們在鍵盤下按的 Ctrl + C 其實就是2號信號,下面我們嘗試對2號信號進行捕捉。

#include <iostream>
#include <signal.h>
#include <unistd.h>

void hander(int sig)
{
    std::cout << "get a signal " << sig << std::endl;
}


int main()
{
    signal(2, hander);
    while (true)
    {
        std::cout << "我正在運行...,我的PID是: " << getpid() << std::endl;
        sleep(1);
    }
    
    return 0;
}

運行結果:

可以看到我們使用 Ctrl + C 已將無法終止進程了,變成了我們自定義的動作了!
【Linux】進程信號之信號的產生,linux,linux,運維,服務器

3、Linux下的信號

Linux下我們可以使用kill -l命令列出所有的信號。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

仔細觀察我們發(fā)現,這里面是沒有32 ,33號信號的!其中從1~31號信號是普通信號,34~64是實時信號。(這里我們主要討論普通信號)

  • 每個信號都有一個編號和一個宏定義名稱,這些宏定義可以在/usr/include/bits/signum.h中找到。
    【Linux】進程信號之信號的產生,linux,linux,運維,服務器
  • 對于普通信號默認的處理動作是什么,在man 7 signal中都有詳細說明。
    【Linux】進程信號之信號的產生,linux,linux,運維,服務器

二、信號的產生

Linux下進程信號的產生是有多種方式的,下面我們就來一起了解一下吧!

1、通過終端按鍵產生信號

Linux下輸入命令可以在Shell下啟動一個前臺進程,當我們想要終止一個前臺進程時,我們可以按下 Ctrl + C 來進行終止這個前臺進程,其實這個 Ctrl + C 也是一個信號,它對應的信號的2號信號SIGINT,這個信號對應的默認處理動作就是終止當前的前臺進程。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

  • 用戶按下 Ctrl-C ,這個鍵盤輸入產生一個硬件中斷 ,被OS獲取,解釋成信號,發(fā)送給目標前臺進程,前臺進程因為收到信號,進而引起進程退出

  • Ctrl-C 產生的信號只能發(fā)給前臺進程。一個命令后面加個&可以放到后臺運行,這樣Shell不必等待進程結束就可以接受新的命令,啟動新的進程,同樣這樣的后臺進程也無法使用Ctrl-C 來進行殺死。

  • Shell可以同時運行一個前臺進程和任意多個后臺進程,只有前臺進程才能接到像 Ctrl-C 這種控制鍵產生的信號。


關于硬件中斷

  • 硬件中斷是由硬件設備觸發(fā)的中斷,當硬件設備有數據或事件需要處理時,會向CPU發(fā)送一個中斷請求,CPU在收到中斷請求后,會立即暫停當前正在執(zhí)行的任務,進入中斷處理程序中處理中斷請求。

關于軟中斷

  • 信號是進程之間事件異步通知的一種方式,屬于軟中斷。

2、調用系統(tǒng)函數向進程發(fā)信號

a、kill函數

【Linux】進程信號之信號的產生,linux,linux,運維,服務器
kill函數是操作系統(tǒng)給我們提供的一個系統(tǒng)調用,通過它我們能夠給指定的進程發(fā)送指定的信號。

  • 參數

    1. 目標進程的pid
    2. 要發(fā)送的信號signal。
  • 返回值:調用成功就返回 0,調用失敗就返回 -1。

kill命令其是就是調用kill函數實現的,下面我們也來模擬實現一下kill命令。

實例代碼:

#include <iostream>
#include <string>
#include <cstdlib>
#include <cerrno>
#include <cstring>
#include <signal.h>
#include <sys/types.h>

void Usage(const std::string proc)
{
    std::cout << "Usage:" << std::endl;
    std::cout << "    " << proc << "   信號編號   目標進程" << std::endl;
}

int main(int argc, char* argv[])
{
    if (argc != 3)
    {
        Usage(argv[0]);
        exit(-1);
    }
    
    pid_t pid = atoi(argv[2]);
    int signo = atoi(argv[1]);
    int return_val = kill(pid, signo);
    if (return_val == -1)
    {
        std::cout << "錯誤碼:" << errno << " 錯誤信息:" << strerror(errno) << std::endl;
    }
    return 0;
}

運行結果:

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

b、raise函數

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

此函數會向當前進程發(fā)送指定的信號

  • 參數: 要發(fā)送的信號sig。

  • 返回值:調用成功就返回 0,調用失敗就返回非0。

實例代碼:

我們用raise函數給當前進程發(fā)送暫停信號19 SIGSTOP ,暫停以后我們可以在命令行中給進程發(fā)送繼續(xù)運行18SIGCONT信號

#include <iostream>
#include <signal.h>
#include <unistd.h>

int main()
{
    sleep(1);
    std::cout << "我要被暫停了,我的PID是:" << getpid() << std::endl;
    
    raise(19);
    
    std::cout << "我要繼續(xù)運行了,我的PID是:" << getpid() << std::endl;
    return 0;
}

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

c、abort函數

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

abort函數使當前進程接收到信號而異常終止,abort函數其實是向進程發(fā)送6號信號SIGABRT,就像exit函數一樣,abort函數總是會成功的,所以沒有返回值,值得注意的是就算6號信號被捕捉了,調用abort函數還是會退出進程。

實例代碼:

#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>

int main()
{
    std::cout << "begin" << std::endl;
    abort();
    std::cout << "end" << std::endl;

    return 0;
}

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

這三個函數只有kill是系統(tǒng)調用,另外兩個都是C庫函數,它們的功能對比如下:

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

3. 由軟件條件產生信號

SIGPIPE是一種由軟件條件產生的信號,在“管道”中已經介紹過了。這里主要介紹alarm函數和SIGALRM信號。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

調用alarm函數可以設定一個鬧鐘,也就是告訴內核在seconds秒之后給當前進程發(fā)14號信號SIGALRM信號, 該信號的默認處理動作是終止當前進程。

  • 參數:鬧鐘的秒數。
  • 返回值:這個函數的返回值有一點特殊,它是是上一次設定的鬧鐘時間還余下的秒數或者是0(0代表上一次的鬧鐘沒有收到干擾,正確的執(zhí)行完了)

實例代碼:

#include <iostream>
#include <signal.h>
#include <unistd.h>

int main()
{
    alarm(1);
    int count = 0;
    while (true)
    {
        std::cout << count++ << std::endl;
    }
    return 0;
}

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

4、硬件異常產生信號

硬件異常產生信號是指硬件產生了錯誤并以某種方式被硬件檢測到并通知內核,然后內核向當前進程發(fā)送適當的信號。

例如當前進程執(zhí)行了除以0的指令,CPU的運算單元會產生異常,內核將這個異常解釋為SIGFPE信號發(fā)送給進程。再比如當前進程訪問了非法內存地址,MMU會產生異常,內核將這個異常解釋為SIGSEGV信號發(fā)送給進程。

例如下面的代碼我們進行除0操作:

#include <iostream>

int main()
{
    int a = 10;
    a /= 0;
    std::cout << a << std::endl;
    return 0;
}

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

在編譯的時候我們收到了一個警告(除0問題),然后我們不管接著運行我們的代碼,然后我們的程序就崩潰了,系統(tǒng)提示是浮點異常問題,其實這個浮點異常問題對應的就是我們的硬件異常,它對應的信號是8號信號SIGFPE

大致原理:在計算機內部是有一個狀態(tài)寄存器的,該寄存器內部是一個位圖結構,如果對應的比特位為1就表示本次計算有數據溢出的情況,說明本次計算結果不正確,CPU執(zhí)行有誤,而操作系統(tǒng)每次調度進程時都會去檢查狀態(tài)寄存器的狀態(tài),確保進程的執(zhí)行的正確性。

當讓CPU執(zhí)行除0操作就會引發(fā)數據溢出的問題,然后狀態(tài)寄存器里面對應的比特位被置為1,我們操作系統(tǒng)檢測到了狀態(tài)寄存器中有比特位被置為1,就會向對應的進程發(fā)送SIGFPE信號終止掉該進程,于是除0就會導致程序崩潰。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

下面我們可以用信號捕捉去驗證我們上面的原理和結論。

#include <iostream>
#include <cstdlib>
#include <signal.h>
#include <unistd.h>

void handler(int sig)
{
    std::cout << "我是收到 " << sig <<"信號才崩潰了"<< std::endl;
}

int main()
{
    signal(SIGFPE, handler);
    int a = 10;
    a /= 0;
    std::cout << a << std::endl;
 
    return 0;
}

運行結果:

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

可以看到我們的程序出現了死循環(huán)的打印,這是因為我們捕捉了8號信號,將原來的默認動作終止進程修改成了打印動作,當我們的進程處理完信號時,操作系統(tǒng)再次調用該進程時,由于上一次的狀態(tài)寄存器里面的比特位沒有被置0,所以操作系統(tǒng)再次調用該進程時,看到的狀態(tài)寄存器的對應比特位為還是1,于是又向該進程發(fā)送8號信號,而我們的自定義動作始終沒有去處理狀態(tài)寄存器,于是就陷入了死循環(huán)當中。

所以我們一般都是捕捉完該信號以后讓該進程直接退出。


下面我們來看野指針引起的硬件異常:

#include <iostream>
#include <signal.h>
#include <unistd.h>

int main()
{
    int* p = nullptr;
    *p = 10;
    std::cout << "野指針問題" << std::endl;
    return 0;
}

運行結果:

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

系統(tǒng)提示我們發(fā)生了段錯誤,對于野指針問題,其實也是我們進程收到了操作系統(tǒng)發(fā)送的信號而崩潰的,這個信號是11號信號SIGSEGV,而這一次硬件異常的是MMU單元(內存管理單元)。

大致原理:由于我們進程使用的地址都是虛擬地址,當我們進程的代碼實際被執(zhí)行時,需要進行虛擬地址到物理地址的轉換,而這個轉換就要借助MMU這個硬件來進行轉換,當我們的MMU在進行地址轉換時,MMU單元在頁表中尋找地址的映射關系并比較讀寫權限是否一致,如果在頁表中找不到映射或者找到了映射但是進行的操作與讀寫權限不一致,就會導致轉換失敗,進而告知操作系統(tǒng),操作系統(tǒng)識別以后就會向對應的進程發(fā)送SIGSEGV信號,從而終止掉該進程。(注意這里對于這個轉換異常,操作系統(tǒng)并沒有修復,如果用戶捕捉了這個信號,也不修復也不退出,也會導致操作系統(tǒng)一直給該進程發(fā)送此信號)

對于0地址可能操作系統(tǒng)根本沒有給0地址建立映射關系,或者建立了映射關系但是操作系統(tǒng)不會允許0地址處發(fā)生寫入!而當我們進行*p = 10時,是需要進行寫入的,MMU在地址轉換時發(fā)現權限不一致,進而引發(fā)給異常,報告給了操作系統(tǒng),然后操作系統(tǒng)向我們的的進場發(fā)送SIGSEGV信號。

【Linux】進程信號之信號的產生,linux,linux,運維,服務器

結語

本章講述的是進程信號的產生,但是只知道這些還是不夠的,下一章我們繼續(xù)深入理解進程信號的保存,提升我們對于信號的理解。

當然如果本篇文章有錯誤或不足的地方,歡迎評論或私信討論!那么我們下期見,byebye!文章來源地址http://www.zghlxwxcb.cn/news/detail-541476.html

到了這里,關于【Linux】進程信號之信號的產生的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網!

本文來自互聯(lián)網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • Linux入門之進程信號|信號產生的方式

    Linux入門之進程信號|信號產生的方式

    文章目錄 一、信號入門 1.linux信號的基本概念 2.使用kill -l 命令可以查看系統(tǒng)定義的信號列表 3.信號處理常見方式 二、產生信號 1.通過終端按鍵產生信號 2.通過調用系統(tǒng)函數向進程發(fā)信號 3.由軟條件產生信號 4.硬件異常產生信號 ??? 1. /0異常 ??? 2.模擬野指針 信號是進程之

    2024年02月09日
    瀏覽(20)
  • 【Linux】進程信號——進程信號的概念和介紹、產生信號、四種產生信號方式、阻塞信號、捕捉信號、阻塞和捕捉信號的函數

    【Linux】進程信號——進程信號的概念和介紹、產生信號、四種產生信號方式、阻塞信號、捕捉信號、阻塞和捕捉信號的函數

    ??在Linux中,進程信號是一種異步的事件通知機制,用于通知進程某個事件已經發(fā)生。它是進程間通信的一種方式,可以用來控制進程的行為。 ??當一個進程收到信號時,操作系統(tǒng)會中斷該進程的正??刂屏鞒?,并執(zhí)行相應的處理函數。進程收到信號后有三種處理方式:

    2024年02月02日
    瀏覽(26)
  • 【Linux】進程信號 --- 信號的產生 保存 捕捉遞達

    【Linux】進程信號 --- 信號的產生 保存 捕捉遞達

    被愛情困住的是傻子 1. 關于信號這個話題我們其實并不陌生,早在以前的時候,我們想要殺死某個后臺進程的時候,無法通過ctrl+c熱鍵終止進程時,我們就會通過kill -9的命令來殺死信號。 查看信號也比較簡單,通過kill -l命令就可以查看信號的種類,雖然最大的信號編號是

    2023年04月23日
    瀏覽(20)
  • 【Linux】進程信號 -- 信號產生 | 系統(tǒng)調用、硬件、軟件的信號發(fā)送

    【Linux】進程信號 -- 信號產生 | 系統(tǒng)調用、硬件、軟件的信號發(fā)送

    kill -l 是一個在 Linux 和 Unix 系統(tǒng)中使用的命令,用于列出可用的信號列表。 在Linux和Unix系統(tǒng)中,進程可以通過發(fā)送信號來與其他進程或操作系統(tǒng)交互。kill 命令可以向指定的進程發(fā)送一個特定的信號,以便對其進行控制,例如終止進程或重新啟動進程等。 kill -l 命令會列出可

    2024年02月16日
    瀏覽(59)
  • 運維記錄 會產生無用日志的服務器

    創(chuàng)建linux定時任務 crontab -e cron表達式 文件名.sh 查看linux定時任務 crontab -l 確認創(chuàng)建完成后重啟cron service crond restart

    2024年04月11日
    瀏覽(18)
  • 【探索Linux】—— 強大的命令行工具 P.16(進程信號 —— 信號產生 | 信號發(fā)送 | 核心轉儲)

    【探索Linux】—— 強大的命令行工具 P.16(進程信號 —— 信號產生 | 信號發(fā)送 | 核心轉儲)

    在現代社會中,信號無處不在。我們的生活充滿了各種各樣的信號,它們指引著我們前進的方向,使我們能夠了解周圍環(huán)境的變化。正如在計算機編程中一樣,Linux進程信號也是一種重要的信號,它們扮演著相似的角色。 想象一下,在繁忙的城市街道上行駛,交通信號燈是我

    2024年02月05日
    瀏覽(17)
  • 【Linux】進程信號(完整版) --- 信號產生 信號保存 信號捕捉 可重入函數 volatile SIGCHLD信號等

    【Linux】進程信號(完整版) --- 信號產生 信號保存 信號捕捉 可重入函數 volatile SIGCHLD信號等

    ?? 作者: 阿潤菜菜 ?? 專欄: Linux系統(tǒng)編程 我們想要殺死某個后臺進程的時候,無法通過ctrl+c熱鍵終止進程時,我們就會通過kill -9的命令來殺死信號。 查看信號也比較簡單,通過 kill -l 命令就可以查看所有信號的種類,雖然最大的信號編號是64,但實際上所有信號只有6

    2024年02月04日
    瀏覽(26)
  • 運維 | 查看 Linux 服務器 IP 地址

    大多數在操作 Linux 系統(tǒng)時,我們經常需要知道服務器的 IP 比便于后續(xù)的一系列操作,這時候有快速查看主機 IP 的命令行操作,能夠有效的幫助我們 本章節(jié)主要記錄一些常用查看服務器 IP 的命令,希望對大家有所幫助。 查看 Linux 服務器的 IP 地址的命令大體上有以下幾種。

    2024年04月27日
    瀏覽(103)
  • 【運維】Linux 跨服務器復制文件文件夾

    如果是云服務 建議用內網ip scp是secure copy的簡寫,用于在Linux下進行遠程拷貝文件的命令,和它類似的命令有cp,不過cp只是在本機進行拷貝不能跨服務器,而且scp傳輸是加密的??赡軙晕⒂绊懸幌滤俣?。當你服務器硬盤變?yōu)橹蛔x read only system時,用scp可以幫你把文件移出來

    2024年02月08日
    瀏覽(109)
  • linux并發(fā)服務器 —— 多進程并發(fā)(四)

    linux并發(fā)服務器 —— 多進程并發(fā)(四)

    程序是包含一系列信息的文件,描述了如何在運行時創(chuàng)建一個進程; 進程是正在運行的程序的實例,可以用一個程序來創(chuàng)建多個進程; 用戶內存空間包含程序代碼以及代碼所使用的變量,內核數據結構用于維護進程狀態(tài)信息; 進程控制塊(PCB):維護進程相關的信息,tas

    2024年02月11日
    瀏覽(27)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包