linux 信號和信號量編程

對于 Linux來說,實際信號是軟中斷,許多重要的程序都需要處理信號。信號,為 Linux 提供了一種處理異步事件的方法。比如,終端用戶輸入了 ctrl+c 來中斷程序,會通過信號機制停止一個程序。
信號概述
信號的名字和編號:
每個信號都有一個名字和編號,這些名字都以“SIG”開頭,例如“SIGIO ”、“SIGCHLD”等等。
信號定義在signal.h頭文件中,信號名都定義為正整數。
具體的信號名稱可以使用kill -l來查看信號的名字以及序號,信號是從1開始編號的,不存在0號信號。kill對于信號0又特殊的應用。

//1)掛起    2)中斷(ctl+c)  3)退出    4)出現了問題   1) SIGHUP	 2) SIGINT	 3) SIGQUIT	 4) SIGILL	 5) SIGTRAP//6)丟棄    7)總線信號                9)殺死進程6) SIGABRT	 7) SIGBUS	 8) SIGFPE	 9) SIGKILL	10) SIGUSR1//                                   14)鬧鐘信號
11) SIGSEGV	12) SIGUSR2	13) SIGPIPE	14) SIGALRM	15) SIGTERM
//                                        19)停止程序
16) SIGSTKFLT	17) SIGCHLD	18) SIGCONT	19) SIGSTOP	20) SIGTSTP
21) SIGTTIN	22) SIGTTOU	23) SIGURG	24) SIGXCPU	25) SIGXFSZ
//                                          29)IO口的訪問
26) SIGVTALRM	27) SIGPROF	28) SIGWINCH	29) SIGIO	30) SIGPWR
31) SIGSYS	34) SIGRTMIN	35) SIGRTMIN+1	36) SIGRTMIN+2	37) SIGRTMIN+3
38) SIGRTMIN+4	39) SIGRTMIN+5	40) SIGRTMIN+6	41) SIGRTMIN+7	42) SIGRTMIN+8
43) SIGRTMIN+9	44) SIGRTMIN+10	45) SIGRTMIN+11	46) SIGRTMIN+12	47) SIGRTMIN+13
48) SIGRTMIN+14	49) SIGRTMIN+15	50) SIGRTMAX-14	51) SIGRTMAX-13	52) SIGRTMAX-12
53) SIGRTMAX-11	54) SIGRTMAX-10	55) SIGRTMAX-9	56) SIGRTMAX-8	57) SIGRTMAX-7
58) SIGRTMAX-6	59) SIGRTMAX-5	60) SIGRTMAX-4	61) SIGRTMAX-3	62) SIGRTMAX-2
63) SIGRTMAX-1	64) SIGRTMAX	

信號的處理:
??????信號的處理有三種方法,分別是:忽略、捕捉和默認動作
??????忽略信號:大多數信號可以使用這個方式來處理,但是有兩種信號不能被忽略(分別是 SIGKILL和SIGSTOP)。因為他們向內核和超級用戶提供了進程終止和停止的可靠方法,如果忽略了,那么這個進程就變成了沒人能管理的的進程,顯然是內核設計者不希望看到的場景
??????捕捉信號:需要告訴內核,用戶希望如何處理某一種信號,說白了就是寫一個信號處理函數,然后將這個函數告訴內核。當該信號產生時,由內核來調用用戶自定義的函數,以此來實現某種信號的處理。
??????系統默認動作:對于每個信號來說,系統都對應由默認的處理動作,當發生了該信號,系統會自動執行。不過,對系統來說,大部分的處理方式都比較粗暴,就是直接殺死該進程。(kill -9 pid 或者 kill -SIGKILL pid)殺死進程
具體的信號默認動作可以使用man 7 signal來查看系統的具體定義。
信號處理函數的注冊
信號處理函數的注冊不只一種方法,分為入門版和高級版
(1)入門版:函數signal
(2)高級版:sigqueue
信號發送函數也不止一個,同樣分為入門版和高級版
(1)入門版:kill
(2)高級版:sigqueue
signal

#include <signal.h>
typedef void (*sighandler_t)(int);//這個是函數指針,沒有返回數,參數是int型,sighandler_t是函數名
sighandler_t signal(int signum, sighandler_t handler);//返回值是sighandler_t,第一個參數signum是要捕捉哪些信號,第二個參數handler是一種類型,指向函數指針void (*sighandler_t)(int)

代碼演示

#include <signal.h>
#include<stdio.h>
// typedef void (*sighandler_t)(int);// sighandler_t signal(int signum, sighandler_t handler);void handler(int signum)//信號處理函數,捕捉信號
{printf("get signal=%d\n",signum);switch(signum){case 2:printf("SIGINT\n");break;case 9:printf("SIGKILL\n");case 10:printf("SIGUSER1\n");}printf("never quite\n");
}
int main()
{signal(SIGINT,handler);//如果將handler改為SIG_ICN即可忽略函數signal(SIGKILL,handler);signal(SIGUSR1,handler);while(1);
}

kill發送消息——低級版

 #include <sys/types.h>#include <signal.h>int kill(pid_t pid, int sig);

代碼實戰

#include <signal.h>
#include<stdio.h>
#include <stdlib.h>
#include <sys/types.h>int main(int argc,char**argv)
{int signum;int pid;char cmd[128]={0};signum=atoi(argv[1]);pid=atoi(argv[2]);//atoi將阿斯科碼轉化為整數printf("num=%d,pid=%d\n",signum,pid);
//      kill(pid,signum);//用來發信號sprintf(cmd,"kill -%d %d",signum,pid);//cmd是目標字符串,第二個參數是想要的目標字符串的長相system(cmd);//用system調用腳本發信號printf("send signal ok\n");return 0;
}

sigaction原型(安裝信號處理程序)

#include <signal.h>
int sigaction(int signum, const struct sigaction *act, struct sigaction *oldact);
//第一個參數是信號,第二個是sigaction結構體用來綁定某些參數,第三個參數也是sigaction結構體,用來備份原有的信號操作,如不需要則設為NULL
struct sigaction {void       (*sa_handler)(int); //信號處理程序,不接受額外數據,SIG_IGN 為忽略,SIG_DFL 為默認動作void       (*sa_sigaction)(int, siginfo_t *, void *); //信號處理程序,能夠接受額外數據和sigqueue配合使用,第一個參數是信號處理函數,第三個是指針空無數據,非空有數據sigset_t   sa_mask;//阻塞關鍵字的信號集,可以再調用捕捉函數之前,把信號添加到信號阻塞字,信號捕捉函數返回之前恢復為原先的值。int        sa_flags;//影響信號的行為SA_SIGINFO表示能夠接受數據};
//回調函數句柄sa_handler、sa_sigaction只能任選其一

關于void (*sa_sigaction)(int, siginfo_t *, void );處理函數來說還需要有一些說明。void 是接收到信號所攜帶的額外數據;而struct siginfo這個結構體主要適用于記錄接收信號的一些相關信息。

 siginfo_t {int      si_signo;    /* Signal number */int      si_errno;    /* An errno value */int      si_code;     /* Signal code */int      si_trapno;   /* Trap number that causedhardware-generated signal(unused on most architectures) */pid_t    si_pid;      /* Sending process ID */uid_t    si_uid;      /* Real user ID of sending process */int      si_status;   /* Exit value or signal */clock_t  si_utime;    /* User time consumed */clock_t  si_stime;    /* System time consumed */sigval_t si_value;    /* Signal value 是結構體*/int      si_int;      /* POSIX.1b signal */void    *si_ptr;      /* POSIX.1b signal */int      si_overrun;  /* Timer overrun count; POSIX.1b timers */int      si_timerid;  /* Timer ID; POSIX.1b timers */void    *si_addr;     /* Memory location which caused fault */int      si_band;     /* Band event */int      si_fd;       /* File descriptor */
}

其中的成員很多,si_signo 和 si_code 是必須實現的兩個成員。可以通過這個結構體獲取到信號的相關信息。
信號發送函數——高級版

#include <signal.h>
int sigqueue(pid_t pid, int sig, const union sigval value);//第一個是發給誰,第二個是發的什么信號,第三個是消息
union sigval {int   sival_int;void *sival_ptr;};

接收端代碼實戰

#include <signal.h>
#include<stdio.h>// int sigaction(int signum, const struct sigaction *act,  struct sigaction *oldact);
void handler(int signum, siginfo_t * info,void * context)
{printf("get signum:%d\n",signum);if(context!=NULL){printf("get data=%d\n",info->si_int);printf("get data=%d\n",info->si_value.sival_int);printf("from: %d\n",info->si_pid);}}
int main()
{struct sigaction act;printf("ps=%d\n",getpid());act.sa_sigaction=handler;//收到信號后調用handle處理信號act.sa_flags=SA_SIGINFO;//SA_SIGINFO表示能接收數據sigaction(SIGUSR1,&act,NULL);while(1);return 0;
}

發送端代碼實戰

#include<stdio.h>
#include <signal.h>
//int  sigqueue(pid_t  pid,  int  sig,  const  union  sigval value);
int main(int argc,char**argv)
{int signum;int pid;signum=atoi(argv[1]);pid=atoi(argv[2]);union sigval value;value.sival_int=100sigqueue(pid,signum,value);printf("pid =%d\n",getpid());printf("over\n");       return 0;
}

臨界資源:
多道程序系統中存在許多進程,它們共享各種資源,然而有很多資源一次只能供一個進程使用。一次僅允許一個進程使用的資源稱為臨界資源。許多物理設備都屬于臨界資源,如輸入機、打印機、磁帶機等。
信號量
信號量(semaphore)與已經介紹過的 IPC 結構不同,它是一個計數器。信號量用于實現進程間的互斥與同步,而不是用于存儲進程間通信數據。
特點

1、 信號量用于進程間同步,若要在進程間傳遞數據需要結合共享內存。

2、信號量基于操作系統的 PV 操作,程序對信號量的操作都是原子操作。

3、 每次對信號量的 PV 操作不僅限于對信號量值加 1 或減 1,而且可以加減任意正整數。

4、 支持信號量組。
原型:
??????最簡單的信號量是只能取 0 和 1 的變量,這也是信號量最常見的一種形式,叫做二值信號量(Binary Semaphore)。而可以取多個正整數的信號量被稱為通用信號量。
??????Linux 下的信號量函數都是在通用的信號量數組上進行操作,而不是在一個單一的二值信號量上進行操作。

#include <sys/sem.h>
// 創建或獲取一個信號量組:若成功返回信號量集ID,失敗返回-1int semget(key_t key, int num_sems,int sem_flags);
// 對信號量組進行操作,改變信號量的值:成功返回0,失敗返回-1
int semop(int semid, struct sembuf semoparray[], size_t numops);  // 控制信號量的相關信息int semctl(int semid, int sem_num, int cmd, ...);

當semget創建新的信號量集合時,必須指定集合中信號量的個數(即num_sems),通常為1; 如果是引用一個現有的集合,則將num_sems指定為 0 。

代碼實戰

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include<stdio.h>
//     int semget(key_t key, int nsems, int semflg);
//int semctl(int semid, int semnum, int cmd, ...);
//int semop(int semid, struct sembuf *sops, unsigned nsops);//取鑰匙的函數,第一個參數是信號量ID,第二個是配置信號量的個數,第三個是第二項的個數
union semun {int              val;    /* Value for SETVAL */struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */unsigned short  *array;  /* Array for GETALL, SETALL */struct seminfo  *__buf;  /* Buffer for IPC_INFO(Linux-specific) */};
void vPutBackKey(int id)
{struct sembuf set;set.sem_num=0;set.sem_op=+1;set.sem_flg=SEM_UNDO;semop(id,&set,1);printf("put back key\n");
}
void pGetKey(int id)
{struct sembuf set;set.sem_num=0;//信號量的編號set.sem_op=-1;//拿鑰匙后原來的鑰匙減一set.sem_flg=SEM_UNDO;//SEM_UNDO表示等待,IPC_NOWAIT表示不等待semop(id,&set,1);printf("get key\n");
}
int main (int argc,char**argv)
{int semid;key_t key=ftok(".",2);semid=semget(key,1,IPC_CREAT|0666);//第二個參數代表信號量集所含信號量個數,flag表示如果沒有信號怎么做。IPC_CREAT表示若信號量不存在則創建它,0666表示信號量的權限union semun initsem;initsem.val=0;//剛開始里面是沒有鑰匙的狀態semctl(sempid,0,SETVAL,initsem);//將信號量初始化,第一個參數是信號量集的ID,第二個參數是代表要操作第幾個信號量 ,0代表第0個。第三個參數是要對信號量如何操作,SETVAL表示設置信號量的值設置為initsem,initsem.val=0表示有一把鑰匙。pid_t pid=fork();if(pid>0){pGetKey(semid);printf("this is father\n");vPutBackKey(semid);semctl(semid,0,IPC_RMID);//銷毀信號量}else if(pid==0){//pGetKey(semid);printf("this is child\n");vPutBackKey(semid);}else{printf("fork error\n");}return 0}

本文參考以下兩篇博文編寫:
信號量
信號

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/272487.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/272487.shtml
英文地址,請注明出處:http://en.pswp.cn/news/272487.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

安卓動畫基礎講解

//逐幀動畫 /** * 1.加入單張圖片 * 2.生成movie.xml整個圖片 * 3.代碼中使用圖片movie.xml */ iv(ImageView) findViewById(R.id.iv);// iv.setImageResource(R.drawable.movie);//為iv加載六張圖片// AnimationDrawable ad(AnimationDrawable) iv.getDrawable();//得到圖片給…

JS一些常用的類庫

一、返回上一頁&#xff08;history&#xff09;發覺有兩種用法&#xff1a;1、javascript:history.back(-1);2、javascript:history.go(-1);它們倆的區別是&#xff1a;history.back(-1):直接返回當前頁的上一頁&#xff0c;數據全部消息&#xff0c;返回新頁面history.go(-1)…

Linux上線程開發API概要(線程)

進程與線程 典型的UNIX/Linux進程可以看成只有一個控制線程&#xff1a;一個進程在同一時刻只做一件事情。有了多個控制線程后&#xff0c;在程序設計時可以把進程設計成在同一時刻做不止一件事&#xff0c;每個線程各自處理獨立的任務。 進程是程序執行時的一個實例&…

Redis學習筆記1-Redis數據類型

Redis數據類型 Redis支持5種數據類型&#xff0c;它們描述如下&#xff1a; Strings - 字符串 字符串是 Redis 最基本的數據類型。Redis 字符串是二進制安全的&#xff0c;也就是說&#xff0c;一個 Redis 字符串可以包含任意類型的數據&#xff0c;一個字符串最大為 512M 字節…

30個非常有趣的404錯誤頁面設計欣賞

當用戶訪問一個不存在的頁面的時候就會出現404錯誤頁面&#xff0c;這對用戶來說是很不友好的。所以很多網站都會去設計一個新穎的錯誤頁面&#xff0c;以吸引用戶繼續瀏覽其它的網頁內容。今天這篇文章就收集了30個非常有趣的404錯誤頁面設計欣賞&#xff0c;希望能帶給你靈感…

線程同步之互斥量加鎖解鎖 死鎖

與互斥鎖相關API 互斥量&#xff08;mutex&#xff09;從本質上來說是一把鎖&#xff0c;在訪問共享資源前對互斥量進行加鎖&#xff0c;在訪問完成后釋放互斥量上的鎖。對互斥量進行加鎖后&#xff0c;任何其他試圖再次對互斥量加鎖的線程將會被阻塞直到當前線程釋放該互…

游戲開發-從零開始 002

個人開發者的游戲大部分需要完成的內容&#xff1a; 1.完整的游戲玩法邏輯&#xff08;核心&#xff09; 2.UI 3.游戲關卡設計 4.游戲旁白 5.交互細節 6.游戲分享接口 7.游戲道具 8.游戲排行榜&#xff0c;游戲社區&#xff0c;如 GameCenter 9.游戲內購 如 remove Ads 10.廣告…

5 個最佳的 Linux 桌面環境

打算把每個桌面都試用一遍&#xff0c;但是那很費時間&#xff0c;而且確實有很多桌面環境可供選擇&#xff0c;這就是我發表“最優秀的 Linux 桌面以及他們的優缺點”的目的&#xff0c;本文告訴你在選擇桌面時需要注意些什么&#xff0c;讓我們開始吧。1. KDE我想從第五個說起…

線程條件控制實現線程的同步

與條件變量相關API 條件變量是線程另一可用的同步機制。條件變量給多個線程提供了一個會合的場所。條件變量與互斥量一起使用時&#xff0c;允許線程以無競爭的方式等待特定的條件發生。 條件本身是由互斥量保護的。線程在改變條件狀態前必須首先鎖住互斥量&#xff0c…

自定義能夠for each的類,C#,Java,C++,C++/cli的實現方法

自定義類能夠被for each&#xff0c;應該算是個老生常談的話題了&#xff0c;相關的資料都很多&#xff0c;不過這里整理總結主流語言的不同實現方式&#xff0c;并比較部分細節上的差異。 第一種語言&#xff0c;也是實現起來最簡單的Java語言。在Java里&#xff0c;要被for e…

SQL Server 2008 R2:快速清除日志文件的方法

本例&#xff0c;快速清理“students”數據庫的日志&#xff0c;清理后日志文件不足1M。USE [master] GO ALTER DATABASE students SET RECOVERY SIMPLE WITH NO_WAIT GO ALTER DATABASE students SET RECOVERY SIMPLE GO USE students GO--此處需要注意&#xff…

linux網絡編程之字節序

進程間通信 特點&#xff1a;依賴于內核&#xff0c;造成缺陷——無法實現多機通信。 網絡編程 地址&#xff1a;由IP地址和端口號構成&#xff0c;端口號用來判斷客戶端接入哪個服務器。 數據的交流&#xff1a;涉及到協議&#xff08;http&#xff0c;tcp&#xff0c;udp&…

Oracle查看表空間和表空間中的對象

select * from user_tables;--查詢所有用戶表 select username,default_tablespace from user_users;--查詢當前表空間select tablespace_name from dba_tablespaces;--查詢所有表空間select tablespace_name, sum(bytes)/1024/1024 from dba_data_files group by tablespace_n…

C#中DateTime.Ticks屬性及Unix時間戳轉換

DateTime.Ticks&#xff1a;表示0001 年 1 月 1 日午夜 12:00:00 以來所經歷的 100 納秒數&#xff0c;即Ticks的屬性為100納秒&#xff08;1Ticks 0.0001毫秒&#xff09;。Unix時間戳&#xff1a;是從1970年1月1日&#xff08;UTC/GMT的午夜&#xff09;開始所經過的秒數&am…

WebBrowser控件的常用方法、屬性和事件

1. 屬性屬性說明Application如果該對象有效&#xff0c;則返回掌管WebBrowser控件的應用程序實現的自動化對象(IDispatch)。如果在宿主對象中自動化對象無效&#xff0c;這個程序將返回WebBrowser 控件的自動化對象Parent返回WebBrowser控件的父自動化對象&#xff0c;通常是一…

二維碼高亮

// 二維碼高亮。http://blog.sina.com.cn/s/blog_a843a8850102uy6w.html 轉載于:https://www.cnblogs.com/muyushifang07/p/5114667.html

socket 網絡 編程

網絡編程場景 自己是客戶端站在5棟樓前&#xff0c;自己要找到5棟樓中的一座并進入某一間房間&#xff0c;這時第二座樓上有人在用漢語&#xff08;tcp/udp&#xff09;說話,我的ip地址&#xff08;樓號&#xff09;是…&#xff0c;我的端口號&#xff08;房間號&#xff09;是…

7個免費的Linux FTP客戶端工具

在Dropbox、YouSendIt、idrive以及許多這樣云存儲和共享工具的幫助下&#xff0c;我們在互聯網上發送和共享大型文件變得容易起來。所有這些網站都可以幫助你在互聯網上傳送文件&#xff0c;但如果你要分享龐大的數據&#xff0c;這依然是很復雜的事情。所以&#xff0c;你需要…

樹莓派的幾種登錄方式及樹莓派的網絡配置

&#xff08;1&#xff09;HDMI 視頻線 連接到顯示器 &#xff08;2&#xff09;串口 設備破解&#xff1a; 默認情況下,樹莓派的串口和藍牙連接&#xff0c;把串口用來數據通信。 修改系統配置&#xff0c;啟用串口登錄樹莓派 1.打開SD卡根目錄的"config.txt"文件…

C語言之常量與變量

1.常量 1.1整型常量:短整型(short int),整型(int),長整型(long int).短整型和長整型都可省慮后面的int,三者唯一的區別就是內存大小的區別,從小到大依次為short < int < long. int a;short int b;long int c;  printf("%d,%d",a,b);  printf("%ld&quo…