1. 程式人生 > >Linux程序入門學習(七)-訊號通訊

Linux程序入門學習(七)-訊號通訊

訊號通訊

什麼是訊號?

在作業系統中,當我們無正常結束一程式時,可以用工作管理員強行結束這個程序。在unix/linux 中,具體的實現過程是通過程序A 生成一個訊號併發射出去,執行中的程序B捕獲到這個訊號然後根據這個訊號的特定意義做出相應的操作。
訊號是UNIX 和Linux 系統響應某些條件而產生的一個事件,接收到該訊號的程序會相應地採取一些行動。訊號的處理實質是能軟體中斷這樣的機制來實現的。
通常訊號是由一個錯誤產生的。但它們還可以作為程序間通訊或修改行為的一種方式,明確地由一個程序傳送給另一個程序。

訊號的種類

在linux 系統中預定義了多種訊號,主要分佈在標頭檔案signal.h 中,訊號都以SIG 開頭。
可以通過以下方式檢視:#kill -l


kill-l
說明:
程式不可捕獲、阻塞或忽略的訊號有:SIGKILL,SIGSTOP
不能恢復至預設動作的訊號有:SIGILL,SIGTRAP
預設會導致程序流產的訊號有:SIGABRT,SIGBUS,SIGFPE,SIGILL,SIGIOT,
SIGQUIT,SIGSEGV,SIGTRAP,SIGXCPU,SIGXFSZ
預設會導致程序退出的訊號有:SIGALRM,SIGHUP,SIGINT,SIGKILL,
SIGPIPE,SIGPOLL,SIGPROF,SIGSYS,SIGTERM,SIGUSR1,SIGUSR2,SIGVTALRM
預設會導致程序停止的訊號有:SIGSTOP,SIGTSTP,SIGTTIN,SIGTTOU
預設程序忽略的訊號有:SIGCHLD,SIGPWR,SIGURG,SIGWINCH

訊號的工作原理

a.程序A 向核心設定程序B 訊號
b.核心管理訊號,並在訊號成立時向程序B 發射訊號
c.程序B 捕獲到訊號並執行響應
signal
整個通訊過程中,不同階段使用不同的介面函式
1)傳送階段

kill 函式
raise 函式
alarm 函式

2)處理階段

signal 函式

3)接收階段

while(1);
sleep();
pause();

下面分別介紹訊號通訊過程中,每個階段所使用到的函式介面

訊號的傳送

kill 函式實現向程序傳送訊號
標頭檔案

#include <sys/types.h>
#include <signal.h>

函式原型

    int kill(pid_t pid, int sig);

返回值

成功:0
失敗:-1

引數列表

pid_t pid:要操作的程序PID
int sig : 傳送的訊號(訊號序號或者訊號名)

示例:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <signal.h>
int main()
{
    int pid,sig;
    while(1)
    {
        printf("please input process pid and sig:\n");
        scanf("%d%d", &pid,&sig);
        //傳送指定訊號給指定程序
        kill(pid,sig);
    }
    return 0;
}

raise 函式用於傳送訊號給自己
標頭檔案

#include <signal.h>

函式原型

int raise(int sig);

返回值

成功返回0,失敗返回非0

引數

Sig:傳送的訊號

示例:使用raise 實現自殺

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

int main()
{

    printf("raise before \n");
    raise(9);
    printf("raise after \n");

    return 0;
}

執行結果:

xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ vi raise.c 
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ gcc raise.c -o  raise
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ ./raise
raise before 
Killed
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ 

以上程式碼中,執行完raise 函式後,並沒有列印raise after,說明raise 設定的訊號是立即有效的。

alarm 函式用於實現延時觸發訊號給自己。
函式說明
用來設定訊號在經過引數seconds 指定的秒數後傳送給目前的程序.
標頭檔案

#include <unistd.h>

函式原型

unsigned int alarm(unsigned int seconds);

引數

seconds,定時時間,單位為秒

返回值

返回之前鬧鐘的剩餘秒數, 如果之前未設鬧鐘則返回0

示例:

#include <stdio.h> 
#include <unistd.h>
#include <signal.h>
int main()
{
    int i=0;
    printf("alarm before \n");
    alarm(9);
    printf("raise after \n");
    while(i<15)
    {
        printf("cnt=%d\n",++i);
        sleep(1);
    }
    return 0;
}

執行結果:

alarm before 
raise after 
cnt=1
cnt=2
cnt=3
cnt=4
cnt=5
cnt=6
cnt=7
cnt=8
cnt=9
Alarm clock
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$

pause 函式用於實現程序的休眠
標頭檔案

#include <unistd.h>

函式原型

int pause(void);

示例:

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

int main(int argc, char **argv)
{
    printf("pid = %d\n", getpid());
    pause();
    printf("pause done \n");

    return 0;
}

執行結果:

xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ ./pause
pid = 3125
^C          //ctrl+c
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$

以上程式碼中,程序呼叫pause 後會一直處理休眠態,這時可以按下ctrl + C 來結束程序。

訊號的處理

通過前面的學習,我們已經知道,當核心接收到訊號後,會在相應時間內對程序作出操作,而這樣的操作都是訊號的預設操作,如
alarm 函式實現的是配置14) SIGALRM 終止程序
ctrl+c 2) SIGINT 終止程序
kill 9) SIGKILL 終止程序
ctrl+z 20) SIGTSTP 暫停程序
可是,在很多實際情況下,當觸發出訊號後,我們並不打算讓核心來中止或者暫停我們的程序,而是中斷跳出處理其他事,完了再回來這時我們該怎麼辦? 可以採用signal 來處理

signal 函式用於獲捕訊號
標頭檔案

#include <signal.h>

函式原型

typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);

返回值

    sighandler_t 是一個函式指標變數,含有一個整形引數,即訊號編號,返回值是void
如果返回負數,則出錯。

引數列表

訊號signum
函式指標sighandler_t handler,是一個系統的回撥函式,可取以下三種情況
a.SIG_IGN 忽略本次觸發的訊號
b.SIG_DFL 採用系統預設的方式處理
c.自定義的訊號處理函式指標

示例:請為SIGALRM 自定義一個對應的處理函式。

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

void alarm_handler(int signum)
{
    int i=0;
    while(i<10)
    {
        printf("alarm handler, signum = %d\n", signum);
        i++;
        sleep(1);
    }
    return ;
}

int main(int argc, char **argv)
{
    int i=0;
    //新增處理函式
    int ret;
    ret = (int)signal(SIGALRM, alarm_handler);
    if(ret < 0)
    {
        printf("fail to signal \n");
        return -1;
    }
    //延遲觸發SIGALRM訊號
    printf("alarm before \n");
    alarm(10);
    printf("alarm after \n");

    while(i<20)
    {
        printf("main handler, cnt = %d\n",++i);
        sleep(1);
    }
    while(1);
    return 0;
}

執行結果:

[email protected]:/mnt/hgfs/share/ISP/pratice8.9$ ./signal
alarm before 
alarm after 
main handler, cnt = 1
main handler, cnt = 2
main handler, cnt = 3
main handler, cnt = 4
main handler, cnt = 5
main handler, cnt = 6
main handler, cnt = 7
main handler, cnt = 8
main handler, cnt = 9
main handler, cnt = 10
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
alarm handler, signum = 14
main handler, cnt = 11
main handler, cnt = 12
main handler, cnt = 13
main handler, cnt = 14
main handler, cnt = 15
main handler, cnt = 16
main handler, cnt = 17
main handler, cnt = 18
main handler, cnt = 19
main handler, cnt = 20

如果把ret = (int)signal(SIGALRM, alarm_handler);中的alarm_handler換成SIG_IGN(遮蔽該訊號),結果將會是如下:

[email protected]:/mnt/hgfs/share/ISP/pratice8.9$ ./signal
alarm before 
alarm after 
main handler, cnt = 1
main handler, cnt = 2
main handler, cnt = 3
main handler, cnt = 4
main handler, cnt = 5
main handler, cnt = 6
main handler, cnt = 7
main handler, cnt = 8
main handler, cnt = 9
main handler, cnt = 10
main handler, cnt = 11
main handler, cnt = 12
main handler, cnt = 13
main handler, cnt = 14
main handler, cnt = 15
main handler, cnt = 16
main handler, cnt = 17
main handler, cnt = 18
main handler, cnt = 19
main handler, cnt = 20

如果把ret = (int)signal(SIGALRM, alarm_handler);中的alarm_handler換成SIG_DFL(恢復預設訊號處理方式),結果將會是如下:

xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$ ./signal
alarm before 
alarm after 
main handler, cnt = 1
main handler, cnt = 2
main handler, cnt = 3
main handler, cnt = 4
main handler, cnt = 5
main handler, cnt = 6
main handler, cnt = 7
main handler, cnt = 8
main handler, cnt = 9
main handler, cnt = 10
Alarm clock
xie@ubuntu:/mnt/hgfs/share/ISP/pratice8.9$

相關推薦

Linux程序入門學習-訊號通訊

訊號通訊 什麼是訊號? 在作業系統中,當我們無正常結束一程式時,可以用工作管理員強行結束這個程序。在unix/linux 中,具體的實現過程是通過程序A 生成一個訊號併發射出去,執行中的程序B捕獲到這個訊號然後根據這個訊號的特定意義做出相應的操作。 訊

Linux程序入門學習-認識程序

1.程序的概念 一個可執行的程式檔案(ELF格式)被載入到記憶體當中,然後讓CPU逐條執行其程式碼,根據程式碼作出相應的動作,這樣一個動態程序就產生了。因此,程序是一個動態變化的過程。 下面用一張圖來表示一個程式從編寫到最終執行的過程: 一段固化在磁碟

Linux程序入門學習-程序啟動退出

1. 程序的退出 exit 函式用於程序退出 標頭檔案:#include <stdlib.h> 函式原型:void exit(int status); 引數:int status:退出狀態值(可以任意寫,值規定0 以上的正整數) 返回值:無

Dynamics CRM 365零基礎入門學習Dynamics 365 DataMigrationUtility tool使用

SDK裡有個工具叫DataMigrationUtility,這個工具適合兩個CRM系統之間的資料遷移。例如:在專案上線之初會做資料初始化的工作,一般這個工作會在UAT開始前完成,當UAT完成之後再把這部分初始化資料遷移到生產環境。那我費了半天勁把資料匯入UAT,難道還要重複一次匯入正式環境嗎

鳥哥的linux私房菜學習-vim程序編輯器

常常 分享 最後一行 編碼 取代 行為 edi 檔案 img 1.vi和vim 在 Linux 的世界中,絕大部分的配置文件都是以 ASCII 的純文本形態存在,因此利用簡單的文字編輯軟件就能夠修改設定了! 常常聽到的就有: emacs, pico, nano, joe

linux入門學習linux圖形化界面與命令行界面之間的切換,以及一些系統命令

之間 linu 鏡像 pan ctr 安裝 linux -- linux鏡像 一、linux圖形化界面與命令行界面之間的切換 註意:前提是你安裝的 linux鏡像ios 必須具備圖形化功能。 1)  圖形化界面--->命令行界面:       ctrl + alt +

Linux學習——vi編輯器

vi —— 終端中的編輯器 目標     01. vi 簡介 1.1 學習 vi 的目的 在工作中,要對 伺服器 上的檔案進行 簡單 的修改,可以使用 ssh 遠端登入到伺服器上,並且使用 vi 進行快速的編輯即可 常見需要

Linux小小白入門教程:vi文字編輯命令

以下操作在Linux終端進行。Linux因為許可權非常嚴格,所以暫時所有的命令操作全部是在/home資料夾下的/yangjw資料夾下進行。/yangjw資料夾就是登入使用者名稱所在的資料夾,出了此資料

Node學習入門:Connect自帶的中介軟體

本章內容 解析cookie、請求主體和查詢字串的中介軟體 實現Web程式核心功能的中介軟體 處理Web程式安全的中介軟體 提供靜態檔案服務的中介軟體 解析cookie、請求主體和查詢字串的中介軟體 常用

程式設計師的機器學習入門筆記:推薦系統入門介紹

介紹 背景 隨著網際網路行業的井噴式發展,獲取資訊的方式越來越多,人們從主動獲取資訊逐漸變成了被動接受資訊,資訊量也在以幾何倍數式爆發增長。舉一個例子,PC時代用google reader,常常有上千條未讀部落格更新;如今的微信公眾號,也有大量的紅點未閱

linux多執行緒學習——實現“生產者和消費者”

在上一篇文章中,利用訊號量實現了執行緒間的互斥,這一篇將要利用訊號量的互斥同步機制來實現一個經典例項,就是“生產者和消費者”。 1、簡單描述生產者和消費者的問題。 有一個緩衝區和兩個執行緒:生產者和消費者。生產者把產品放入緩衝區,而消費者從緩衝區中拿走。當緩衝區滿時,生產者必

hexo入門學習:文章圖片儲存到牛雲

詳情請檢視個人部落格文章圖片儲存到七牛雲   轉載請註明出處!   前幾天開啟blog發現使用前文中的方法原方法 文章中的圖片莫名奇妙的掛了。查閱資料(百度、谷歌)。發現七牛雲端儲存可以很好的解決這個問題。於是根據下面這篇文章基本解決了問題。 參考文

Linux執行緒入門學習-認識執行緒

1. 執行緒的概念 執行緒,又稱輕量級程序,是程序中執行運算的最小單位,是程序中的一個實體,是被系統獨立排程和分派的基本單位,主要有以下特點: 1)執行緒自己不擁有系統資源,只擁有一點在執行中必不可少的資源; 2)與同屬一個程序的其它執行緒共享程序所擁有的全

基於PyTorch的深度學習入門教程——PyTorch重點綜合實踐

前言 PyTorch提供了兩個主要特性: (1) 一個n維的Tensor,與numpy相似但是支援GPU運算。 (2) 搭建和訓練神經網路的自動微分功能。 我們將會使用一個全連線的ReLU網路作為例項。該網路有一個隱含層,使用梯度下降來訓練,目標是最小化

Linux多工程式設計---Linux守護程序及其基礎實驗

守護程序概述    守護程序,又叫daemon程序(不知怎的,我突然想起來吸血鬼日記中的達蒙了,很好看的美劇),是Linux中的後臺服務程序。他是一個生存期較長的程序,通常獨立於控制終端並且週期性地執行某種任務或者等待處理某些發生的事件。守護程序常常在系統引導載入時啟動,在

Ubuntu Linux 菜鳥正在入門學習——檔案系統的概念

1.什麼是檔案系統      檔案系統是對一個儲存裝置上的資料和元資料進行組織的機制,其目的是易於實現資料的查詢和存取。Linux檔案系統介面實現為分層的體系結構,從而將使用者介面層 檔案系統實現和操作儲存裝置的驅動程式分開。 1)儲存介質 用以儲存資料的物理裝置,如軟盤

JAVA學習:方法重載與方法重寫、thiskeyword和superkeyword

格式 hello new 初始 per 而且 方法重寫 學習 方式 方法重載與方法重寫、thiskeyword和superkeyword 1、方法重載 重載可以使具有同樣名稱但不同數目和類型參數的類傳遞給方法。 註: 一是重載方法的參數列表必須與被重載的方法不同

Linux服務器學習

-1 修改 感覺 img size 地址 mage 第一次 spa 一、首先連接服務器   下載一個windows下連接linux的ssh工具,我這裏用的putty。一次填入HostName(主機名,可以是服務器域名也可以是對應的ip)、Port(端口號默認為22)、Co

Guice 學習常量和屬性的註入 Constant and Property Inject

-a ret roc build ann class google mes ota 1、常量註入方式 package com.guice.ConstantInjectDemo; import com.google.inject.Binder; i

[linux][MongoDB] mongodb學習:MongoDB安裝、管理工具、

ole ont mon mkdir man 管理工具 tar end 認證 參考原文:http://www.cnblogs.com/kaituorensheng/p/5118226.html linux安裝完美實現! 1. mongoDB安裝、啟動、關閉   1.1