内蒙古住房与建设厅网站,自己怎么做网页推广,网页微信注册新号怎么注册,wordpress 第一张图片不显示对于 Linux来说#xff0c;实际信号是软中断#xff0c;许多重要的程序都需要处理信号。信号#xff0c;为 Linux 提供了一种处理异步事件的方法。比如#xff0c;终端用户输入了 ctrlc 来中断程序#xff0c;会通过信号机制停止一个程序。 信号概述 信号的名字和编号实际信号是软中断许多重要的程序都需要处理信号。信号为 Linux 提供了一种处理异步事件的方法。比如终端用户输入了 ctrlc 来中断程序会通过信号机制停止一个程序。 信号概述 信号的名字和编号 每个信号都有一个名字和编号这些名字都以“SIG”开头例如“SIGIO ”、“SIGCHLD”等等。 信号定义在signal.h头文件中信号名都定义为正整数。 具体的信号名称可以使用kill -l来查看信号的名字以及序号信号是从1开始编号的不存在0号信号。kill对于信号0又特殊的应用。
//1)挂起 2中断(ctlc) 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) SIGRTMIN1 36) SIGRTMIN2 37) SIGRTMIN3
38) SIGRTMIN4 39) SIGRTMIN5 40) SIGRTMIN6 41) SIGRTMIN7 42) SIGRTMIN8
43) SIGRTMIN9 44) SIGRTMIN10 45) SIGRTMIN11 46) SIGRTMIN12 47) SIGRTMIN13
48) SIGRTMIN14 49) SIGRTMIN15 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
#includestdio.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.hint kill(pid_t pid, int sig);代码实战
#include signal.h
#includestdio.h
#include stdlib.h
#include sys/types.hint main(int argc,char**argv)
{int signum;int pid;char cmd[128]{0};signumatoi(argv[1]);pidatoi(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
#includestdio.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_sigactionhandler;//收到信号后调用handle处理信号act.sa_flagsSA_SIGINFO;//SA_SIGINFO表示能接收数据sigaction(SIGUSR1,act,NULL);while(1);return 0;
}发送端代码实战
#includestdio.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;signumatoi(argv[1]);pidatoi(argv[2]);union sigval value;value.sival_int100sigqueue(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
#includestdio.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_num0;set.sem_op1;set.sem_flgSEM_UNDO;semop(id,set,1);printf(put back key\n);
}
void pGetKey(int id)
{struct sembuf set;set.sem_num0;//信号量的编号set.sem_op-1;//拿钥匙后原来的钥匙减一set.sem_flgSEM_UNDO;//SEM_UNDO表示等待IPC_NOWAIT表示不等待semop(id,set,1);printf(get key\n);
}
int main (int argc,char**argv)
{int semid;key_t keyftok(.,2);semidsemget(key,1,IPC_CREAT|0666);//第二个参数代表信号量集所含信号量个数flag表示如果没有信号怎么做。IPC_CREAT表示若信号量不存在则创建它0666表示信号量的权限union semun initsem;initsem.val0;//刚开始里面是没有钥匙的状态semctl(sempid0SETVALinitsem);//将信号量初始化第一个参数是信号量集的ID第二个参数是代表要操作第几个信号量 0代表第0个。第三个参数是要对信号量如何操作SETVAL表示设置信号量的值设置为initseminitsem.val0表示有一把钥匙。pid_t pidfork();if(pid0){pGetKey(semid);printf(this is father\n);vPutBackKey(semid);semctl(semid,0,IPC_RMID);//销毁信号量}else if(pid0){//pGetKey(semid);printf(this is child\n);vPutBackKey(semid);}else{printf(fork error\n);}return 0
}本文参考以下两篇博文编写 信号量 信号