1. 程式人生 > >作業系統 — 淺析訊號

作業系統 — 淺析訊號

淺析訊號

首先每個訊號都有一個名字,這些名字都以3個字元SIG開頭.例如,SIGABRT是夭折訊號,當程序呼叫abort函式時產生這種信號.SIGALRM是鬧鐘信號,由alarm函式設定的定時器超時後將產生這種訊號. 訊號的種類是非常龐大的. 在標頭檔案<signal.h>中,訊號名都被定義為正整數常量(訊號編號).實際上,實現將各訊號定義在另一個頭檔案中,但是該標頭檔案又包括在<signal.h>中.核心包括對使用者級應用程式有意義的標頭檔案,這被認為一種不好的形式,so如若應用程式和核心兩者都需使用同一定義,那麼就將有關資訊放置在核心標頭檔案當中,然後使用者級檔案再包括該核心頭
件.實際上,不包括編號為0的訊號,kill函式對編號0有特殊的應用. 當然在生活中產生訊號的條件非常之多:1.比如當用戶按某些終端鍵時,引發終的訊號. 2.硬體異常產生訊號  3.程序呼叫Kill 使用者可用kill(1)命令將訊號傳送給其他程序. 4.當檢測到某種軟體條件已經發生,並應將其通知有關程時也產生訊號..

訊號分為可靠訊號和不可靠訊號

不可靠訊號:又叫非實時訊號,linux的訊號繼承unix,所以會有一點問題. 1.在unix訊號中,一旦訊號抵達了,訊號執行了自己的訊號處理函式之後,訊號在核心中將自己的訊號處理方式就會恢復至預設,不過我們的Linux對這種情況進行了優化已經解決了問題. 2.在unix系統下會導致訊號丟
,也就是瞬間來到了許許多多個訊號,最多隻能處理一個訊號(訊號丟失),這種情況下linux沒有進行優化,其實是擁有解決方法:比如對訊號進行排隊等等但是呢! 因為linux現在已經用了這麼多年了,很多基於避免訊號丟失的程式碼已經寫成了,所以對於Linux來說,就算你現在有更好的解決方法,但是你不能夠更改1-31號訊號的結構. 通俗的來說,就是你在蓋樓,當你蓋到50層的時候,發現第一層有一點小小的問題. 而這49層又基於第一層,你不可能因為這個小問題而讓49層樓重新蓋吧?可靠訊號:又叫實時訊號,也就是說1.訊號在執行自己的訊號處理函式之後,訊號在核心中的處理方式不會恢復回預設! 2.不會出現訊號的丟失
.

其實我們64個訊號當中,34-64號訊號全都是可靠的訊號,但是這些函式使用者不能使用. 那些都是系統用來處理執行緒當中的問題的.

處理訊號

在某個訊號出現時,可以告訴核心按下列3種方式之一進行處理,我們稱之為訊號的處理或與訊號相關的動作.1.忽略此訊號. 大多數訊號都可使用這種方式處理,但是有兩種訊號絕對不會被忽略. 它們是SIGKILL和SIGSTOP. 這兩種訊號不能被忽略的原因是:們向核心和超級使用者提供了使程序終止或者停止的可靠方法. 另外,如果忽略某些由硬體異常產生的訊號,則此程序的執行行為是未定義的.2.捕捉訊號. 為了做到這一點,要通知核心在某種訊號發生時,呼叫一個使用者函式. 在使用者函式中,可執行使用者希望對這種事件進行的處理. 例如,若正在編寫一個命令直譯器,它將使用者的輸入解釋為命令並執行之,當用戶用鍵盤產生中斷訊號時,很可能希望該命令直譯器返回到主迴圈,終止正在為該使用者執行的命令. 如果捕捉到SIGCHLD訊號,則表示一個子程序已經終止,所以此訊號的捕捉函式可以呼叫waitpid以取得該子程序的進程ID以及它的終止狀態. 所以我們總結一點! 不能捕捉SIGKILL和SIGSTOP這兩個訊號3.執行系統的預設動作. 下圖就是一些訊號的說明和系統預設動作! 我們看到大多數訊號的系統預設動作是終止該程序.
絕大部分訊號的預設動作無外乎就是五種!
core dumped:將你的記憶體相關退出資訊,儲存到core檔案中,以便於你以後檢視.IGN:告訴父程序,子程序已經執行結束等待回收term:什麼也不做直接死亡cont:程式進行執行stop:讓你的程式暫停.在系統預設動作列,"終止+core"表示在程序當前工作目錄的core檔案中複製了該程序的記憶體映像(該檔名為core,由此可以看出這種功能很久之前就是UNIX的一部分). 大多數UNIX系統除錯程式都使用core檔案檢查程序終止時的狀態. 在下列條件下不產生core檔案: (a)程序是設定使用者ID的,而且當前使用者並非程式檔案的所有者; (b)程序是設定組ID的,而且當前使用者並非該程式檔案的組所有者; (c)檔案太大.  core檔案的許可權通常是使用者讀寫.我們的訊號其實也叫做"軟中斷". 何為中斷? 硬體的中斷:正在執行的硬體,突然被打斷去做另外一個事情,然後完成後又回來繼續執行剛剛沒做完的事情. 所以呢訊號就是在軟體上的對中斷的模擬. 提到訊號大家絕壁會想到一個指令! kill指令. 我們平時使用Kill來發送訊號,所以對他就很眼熟,其實呢kill指令的底層是使用kill函數構成的! 所以呢我們來認識一下這個函式:

kill函式

kill命令就是通過呼叫kill函式生成的,kill函式的作用可大了. kill函式將訊號傳送給核心,然後呢核心根據訊號的對應操作對指定的程序進行執行.比如你向一個程序傳送SIGKILL訊號,那麼核心就會終止掉這個程序! 我們繼續來了解它的情況:
 #include <sys/types.h>
 #include <signal.h>

 int kill(pid_t pid, int sig);
pid引數就是你訊號傳送至的程序ID,後面的sig就是傳送那個訊號. 對於pid引數有好幾種情況分別為:pid > 0  : 給指定的pid傳送訊號                                 pid = 0  :本程序組的任何一個程序傳送訊息.pid = -1 : 給任何有權傳送訊號的程序傳送訊號                    pid < -1 :|pid|的程序組傳送訊號.

訊號的阻塞

實際執行訊號的處理動作稱為訊號遞達,訊號從產生到遞達之間的狀態稱之為訊號未決,程序可以選擇性的阻塞某個訊號,被阻塞的訊號產生時將保持在未決狀態,知道程序解除對此訊號的阻塞,才執行實際執行訊號的處理動作稱為訊號遞達,訊號從產生到遞達之間的狀態,稱為訊號未決.進程可以選擇阻塞某個訊號。 被阻塞的信號產生時將保持在未決狀態,直到程序解除對此訊號的阻塞,才執行遞達的動作. 阻塞和忽略是不相同的,只要訊號被阻塞就不會遞達,而忽略是在遞達之後可選的一種處理動作.達的動作,阻塞和忽略是不相同的,只要訊號被阻塞就不會遞達,而忽略是在遞達之後可以選擇的一種處理動作!
在PCB當中,分別使用了pending,block,handler三個表項來分別記錄 訊號是否遞達,應該讓那些訊號阻塞,每個訊號對應的處理函式. 每個訊號都有兩個標誌位分為表示阻塞和未決,還有一個函式指標表處理動作.訊號產生時,核心在程序控制塊中設定該訊號的未決標誌,直到訊號遞達才消除該標誌.如果在程序在阻塞某訊號時,該訊號產生過多次,Linux是這樣實現的:常規訊號在抵達之前產生多次只計一次,而實時訊號在抵達之前產生多個信號可以依次放到一個佇列中,每個訊號只能有一個bit的未決標誌,非0既1,不記錄該訊號產生了多少次,阻塞標誌也是這樣表示的. 因此呢,未決和阻塞標誌可以用想用的資料型別sigset_t來儲存,sigset_t為訊號集,這個型別可以表示每個訊號的"有效"或"無效"狀態,在阻塞訊號集中"有效"和"無效"的含義是該訊號是否被阻塞,而在未決訊號集中類似. 阻塞訊號集也叫做當前程序的訊號遮蔽字,遮蔽這樣理解"是阻塞 不是忽略".

常見訊號處理函式

//sigset_t型別對於每種訊號用一個bit表示 "有效"或者"無效" 接下來我們來認識一下訊號集操作函式
#Include<signal.h>

int sigemptyset(sigset_t *set);
//初始化set所指向的訊號集,使其中所有訊號的對應的bit清零,表示該訊號集不包含任何有效訊號.

int sigfillset(sigset_t *set);
//初始化set所指向的訊號集,使其中所有訊號的對應bit置位,表示該訊號機的有效訊號包括系統支援的所有訊號.

int sigaddset(sigset_t *set,int signo);
//在該訊號集中新增某種有效訊號.

int sigdelset(sigset_t *set,int signo);
//在該訊號集中刪除某種有效訊號

int sigismemeber(const sigset_t *set,int signo);
//是一個布林函式,用於判斷一個訊號集的有效訊號中是否包含某種訊號,若包含則返回1,不包含則返回0,出錯返回-1

int sigprocmask(int how,const sigset_t *set,sigset_t *oset);
//讀取或更改程序的訊號遮蔽字(阻塞訊號集)如果成功返回0 失敗返回-1

int sigpending(sigset_t *set);
//讀取當前程序的未決訊號集,通過set引數傳出,呼叫成功則返回0,出錯則返回-1.
在這裡我們著重介紹一下sigset_t的結構,我們來看看他究竟是一個什麼東西:
typedef struct
{
    unsigned long int __val[_SISSET_NWORDS];
}__sigset_t;
當你定義了一個sigset_t變數的時候,一定要要記住!! 使用sigemptyset()函式對變數初始化,否則訊號集可能會出現隨機值!!

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

how: 
SIG_BLOCK: mask = mask = mask | set;
SIG_UNBLOCK: mask = mask & ~set;
SIG_SETMASK: mask = set;
//往核心當中設定,儲存阻塞訊號的狀態.
sigprocmask的返回值如果失敗返回-1 成功返回為0. 接下來我實現一個關於訊號阻塞的例項,用來打印出block表當中的內容. 也就是說打印出被阻塞的訊號. 那麼話不多說我們開始寫程式碼:
#include<stdio.h>
#include<signal.h>
#include<unistd.h>

void printsigset(sigset_t *set)
{
	int i = 0;
	for(;i<32;i++){
		if(sigismember(set,i))
			putchar('1');
		else
			putchar('0');
	}
	puts("");
}

int main()
{
	sigset_t s,p;
	sigemptyset(&s);
	sigaddset(&s,SIGINT);
	sigprocmask(SIG_BLOCK,&s,NULL);
	while(1)
	{
		sigpending(&p);
		printsigset(&p);
		sleep(1);
	}
	return 0;
}
接下來帶上程式碼註釋:

這個程式的大概意思就是 我們阻塞一個訊號集,讓它一直處於未決狀態,並把它裡面的訊號編號顯示出來,比如中途我們加入了一個ctrl+c. 後面訊號集裡面就會出現這個訊號,然後他們還是一直處於未決狀態. 我們來看看結果:

特別提醒:如果一個訊號被程序阻塞,它就不會傳遞給程序,但會停留在待處理狀態,當程序解除對待理訊號的阻塞時,待處理訊號就會立刻被處理. 如果掌握了這些之後,我覺得我們就可以繼續學習訊號! 訊號的捕捉. <-----部落格傳送門

相關推薦

作業系統淺析訊號

淺析訊號首先每個訊號都有一個名字,這些名字都以3個字元SIG開頭.例如,SIGABRT是夭折訊號,當程序呼叫abort函式時產生這種信號.SIGALRM是鬧鐘信號,由alarm函式設定的定時器超時後將產

Qt編譯錯誤:底層由於接收到作業系統訊號而停止

double vec = ((m_game->startpos-endPos)*4).length(); /* char Info[24]; sprintf(Info,"%0.2f",sqrt(vec)); m_lable->setT

作業系統訊號的基本操作

一、基本概念 1、中斷 中止(暫停)當前正在執行的任務,轉而執行其他任務,這種行為叫中斷。 硬體中斷:來自硬體的中斷。 軟體中斷:來子軟體的中斷。 2、訊號是一種軟體中斷 它為程序非同步執行任務提供了一種機制。 1) SIGHUP 2) SIGINT 3) SIGQ

機器人作業系統淺析-學習總結

第1章 緒論機器人作業系統淺析書本結構第2章 入門概述1.功能包/軟體包(Packages):在ROS中,所有軟體都被組織為軟體包的形式,稱為ROS軟體包或功能包,有時也簡稱為包。ROS軟體包是一組用於實現特定功能的相關檔案的集合,包括可執行檔案和其他支援檔案。2.節點管理器

作業系統 — 捕捉訊號

如果訊號的處理動作是終止程序,則程序終止,pause函式沒有機會返回; 如果訊號的處理動作是忽略,則程序進行處於掛起狀態,pause不返回; 如果訊號的處理動作是捕捉,則呼叫了訊號處理函式之後pause返回-1現在明白了sig_alrm的作用了吧?? 2.為什麼要在Mysleep函式返回前要回復SIGALRM

作業系統訊號量和管程

訊號量 semaphore 訊號量是作業系統提供的一種協調共享資源訪問的方法 軟體同步是平等執行緒間的一種同步協商機制 OS是管理者,地位高於程序 用訊號量表示系統資源的數量 由一個整形 (sem)變數和兩個原子操作組成 P()(Prolaa

作業系統-使用訊號量實現生產者與消費者(C++實現)

常用函式: HANDLE WINAPI CreateSemaphore(                  _In_opt_  LPSECURITY_ATTRIBUTES lpSemaphoreAttributes   _In_      LONG lInitialCoun

作業系統訊號量與P、V操作

知識點: 訊號量機制主要有整形訊號量、記錄性訊號量、訊號量集機制。 訊號量是一個整形變數,根據控制物件的不同賦不同的值。訊號量可分為公用訊號量和私用訊號量兩類。 公用訊號量:實現程序間的互斥,初值=1或資源的數目 私用訊號量:實現程序間的同步,初值=0或某個整數 訊

作業系統訊號量 程序互斥 同步等概念

Var s:semaphore:=1; /*設定訊號量 s 的初值為 1*/ begin parbegin /*併發開始*/ process1: begin repeat P(s) ; critical section V(s) ; remainder section until fals

作業系統訊號量和自旋鎖的區別

訊號量: 訊號量作為在多核和單核作業系統中都廣泛使用的一種處理機制,在處理衝突問題上有重要作用。 訊號量僅僅是與一個數據結構有關的計數器,所有核心執行緒在試圖訪問這個資料結構之前,都需要檢查這個訊號量,可以把每個訊號量看成一個物件。 組成如下: 一個整

作業系統 程序間的通訊 之 訊號 訊息佇列 共享記憶體 淺析

訊息佇列其實就是一個訊息的連結串列,每個訊息佇列有一個佇列頭,稱為struct msg_queue,這個佇列頭描述了訊息佇列的key值,使用者ID,組ID等資訊,但它存於核心中。而結構體struct msqid_ds能夠返回或設定訊息佇列的資訊,這個結構體位於使用者空間中,與msg_queue結構相似訊息佇列

作業系統 自旋鎖+訊號量+互斥量+臨界區+死鎖的區別

自旋鎖(SpinLock) 自旋鎖是專為防止多處理器併發而引入的一種鎖。如果是單核處理器,則自旋鎖定義為空操作,因為簡單的關閉中斷即可實現互斥。   自旋鎖最多隻能被一個執行緒持有,如果一個執行緒試圖請求一個已被爭用(已被另一個執行緒持有)的自旋鎖,那麼等待自旋鎖的執行緒將會反

作業系統,核心定時器:使用“訊號”建立一種使用者空間機制來測量一個多執行緒程式的執行時間。

      核心是一個作業系統的核心。它負責管理系統的程序、記憶體、裝置驅動程式、檔案和網路系統,決定著系統的效能和穩定性。 定時器是Linux提供的一種定時服務的機制,它在某個特定的時間喚醒某個程序來進行工作。核心在時鐘中斷髮生後檢測各定時器是否到期,在li

作業系統(11)程序--程序通訊:訊號、管道、訊息佇列、共享記憶體

文章目錄 1. 程序通訊相關概念 1. 通訊流程、屬性、鏈路 2. 程序通訊方式:直接通訊、間接通訊 2. 程序通訊的機制 1. 訊號 2. 管道 3. 訊息佇列

作業系統(9)程序--訊號量、管程、經典同步問題

文章目錄 1. 訊號量 1. 訊號量相關概念 2. 訊號量的使用 2. 管程 3. 經典同步問題 1. 訊號量   在上節中,提到了併發和同步,其中,

易學筆記-系統分析師考試-第3章 作業系統基本原理/3.2 程序管理/3.2.2 訊號量與PV操作

程序制約方式 間接相互制約:也稱為程序互斥;程序A與程序B都需要資源C(例如印表機),系統已將C分配給A使用,等待A使用完成後系統再將C分配給B使用 直接相互制約:也稱為程序同步;A通過緩衝區向B提供資料,當緩衝區為空時B不能獲取資料而阻塞;當A把資料放入緩衝區後B將被喚醒

機器人作業系統(ROS)淺析(肖軍浩 博士 譯) 學習筆記二(第六章到第十章)

第 6 章 啟動檔案  利用啟動檔案一次性配置和執行多個節點 。  roslaunch :這是一個自適應工具,如果啟動多節點時沒有節點管理器執行,它會自動啟動節點管理器;如果已經有一個節點 管理器在執行,則會使用已有的。     利用啟動檔案一次性配

機器人作業系統(ROS)淺析(肖軍浩 博士 譯) 學習筆記一(第一章到第五章)

機器人作業系統(ROS)淺析(肖軍浩 博士 譯) 學習筆記 第一章: 第 1 章 緒論 1.1 選擇 ROS 的理由  分散式計算 現代機器人系統往往需要多個計算機同時執行多個 程序,例如:   (1)一些機器人搭載多臺計算機,每臺計算機用於控制機器人的 部分驅動器或感測器

作業系統 程序同步訊號

~~ 一、訊號量機制 ~~ 1、整型訊號量 1)訊號量定義為一個整型量; 2)根據初始情況賦相應的值; 3)僅能通過兩個原子操作來訪問。 整型訊號量符合“有限等待”原則 signal釋放資源後,當CPU被分配給等待程序後,等待程序仍可繼續執行,可以符合“有限等待”。 但整型訊號量

Java併發程式設計實戰————Semaphore訊號量的使用淺析

引言 本篇部落格講解《Java併發程式設計實戰》中的同步工具類:訊號量 的使用和理解。 從概念、含義入手,突出重點,配以程式碼例項及講解,並以生活中的案例做類比加強記憶。 什麼是訊號量 Java中的同步工具類訊號量即計數訊號量(Counting Semaphore),是