日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 运维知识 > linux >内容正文

linux

linux 信号和信号量编程

發(fā)布時(shí)間:2023/12/10 linux 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 linux 信号和信号量编程 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

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

//1)掛起 2)中斷(ctl+c) 3)退出 4)出現(xiàn)了問題 1) SIGHUP 2) SIGINT 3) SIGQUIT 4) SIGILL 5) SIGTRAP//6)丟棄 7)總線信號 9)殺死進(jìn)程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

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

#include <signal.h> typedef void (*sighandler_t)(int);//這個(gè)是函數(shù)指針,沒有返回?cái)?shù),參數(shù)是int型,sighandler_t是函數(shù)名 sighandler_t signal(int signum, sighandler_t handler);//返回值是sighandler_t,第一個(gè)參數(shù)signum是要捕捉哪些信號,第二個(gè)參數(shù)handler是一種類型,指向函數(shù)指針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)//信號處理函數(shù),捕捉信號 {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即可忽略函數(shù)signal(SIGKILL,handler);signal(SIGUSR1,handler);while(1); }

kill發(fā)送消息——低級版

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

代碼實(shí)戰(zhàn)

#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將阿斯科碼轉(zhuǎn)化為整數(shù)printf("num=%d,pid=%d\n",signum,pid); // kill(pid,signum);//用來發(fā)信號sprintf(cmd,"kill -%d %d",signum,pid);//cmd是目標(biāo)字符串,第二個(gè)參數(shù)是想要的目標(biāo)字符串的長相system(cmd);//用system調(diào)用腳本發(fā)信號printf("send signal ok\n");return 0; }

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

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

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

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 是結(jié)構(gòu)體*/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 是必須實(shí)現(xiàn)的兩個(gè)成員。可以通過這個(gè)結(jié)構(gòu)體獲取到信號的相關(guān)信息。
信號發(fā)送函數(shù)——高級版

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

接收端代碼實(shí)戰(zhàn)

#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;//收到信號后調(diào)用handle處理信號act.sa_flags=SA_SIGINFO;//SA_SIGINFO表示能接收數(shù)據(jù)sigaction(SIGUSR1,&act,NULL);while(1);return 0; }

發(fā)送端代碼實(shí)戰(zhàn)

#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; }

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

1、 信號量用于進(jìn)程間同步,若要在進(jìn)程間傳遞數(shù)據(jù)需要結(jié)合共享內(nèi)存。

2、信號量基于操作系統(tǒng)的 PV 操作,程序?qū)π盘柫康牟僮鞫际窃硬僮鳌?/p>

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

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

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

當(dāng)semget創(chuàng)建新的信號量集合時(shí),必須指定集合中信號量的個(gè)數(shù)(即num_sems),通常為1; 如果是引用一個(gè)現(xiàn)有的集合,則將num_sems指定為 0 。

代碼實(shí)戰(zhàn)

#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);//取鑰匙的函數(shù),第一個(gè)參數(shù)是信號量ID,第二個(gè)是配置信號量的個(gè)數(shù),第三個(gè)是第二項(xiàng)的個(gè)數(shù) 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);//第二個(gè)參數(shù)代表信號量集所含信號量個(gè)數(shù),flag表示如果沒有信號怎么做。IPC_CREAT表示若信號量不存在則創(chuàng)建它,0666表示信號量的權(quán)限union semun initsem;initsem.val=0;//剛開始里面是沒有鑰匙的狀態(tài)semctl(sempid,0,SETVAL,initsem);//將信號量初始化,第一個(gè)參數(shù)是信號量集的ID,第二個(gè)參數(shù)是代表要操作第幾個(gè)信號量 ,0代表第0個(gè)。第三個(gè)參數(shù)是要對信號量如何操作,SETVAL表示設(shè)置信號量的值設(shè)置為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}

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

總結(jié)

以上是生活随笔為你收集整理的linux 信号和信号量编程的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。