第六章信号与信号处理
- 6.1信号和中断
由I/O设备或者协议处理器发送到外部请求,它将CPU从正常执行转移到中断处理。
(1)人员中断,人员再次上线后能够继续之前的事项
(2)进程中断,来源如下
1.硬件中断
2.来自其他进程
3.自己造成(除以0,无效地址)
(3)硬件中断,情况如下
1.来自硬件
2.来自其他处理器的中断
3.自己造成
(4)进程的陷阱错误 - 6.2Unix/Linux信号示例
(1)Ctrl+C 终止当前进程。键盘中断处理程序将Ctrl+C转换成SIGINT(2)信号,发送给终端上的进程。在内核模式下,每个进程都要检查和处理未完成的信号,进程对绝大多数信号是调用系统内核的kexit(exitValue)函数来终止。Linux中exitValue的低位字节是导致进程终止的信号。
(2)Nohup a.out &命令在后台运行一个程序。及时用户退出程序依然执行。忽略SIGINT(1)信号。当用户退出时sh会向子程序发送SIGHUP信号,子程序忽略之。
(3)Kill pid (or kill -s 9 pid)杀死进程,执行杀死的进程向pid标识的目标发送SIGTERM(15)信号,请求它死亡。如果拒绝使用括号中的强制执行。 - 6.3 Unix/Linux中的信号处理
(1)型号类型(signal.h)
(2)信号来源
·硬件中断
1.中断键SIGINT(2)
2.间隔定时器SIGALRM(14)、SIGVTALRM(26)、SIGPROF(27)
3.总线错误、IO陷阱
·异常
如通常陷阱信号SIGEPE(8)表示除以0,SIGSEGV(11)段错误
·其他进程
进程使用kill(pid,sig)。杀死无限循环进程。
(3)进程PROC结构体中的信号
每个进程PROC都有一个32位的向量,用来记录发送给程序的信号。位向量中每一位表示信号编号(0位除外),一个信号MASK位向量,用来屏蔽相应信号,使用sigmask、sigsetmask、siggetmask、sigblock等来设置、清除、检查MASK信号。
(4)信号处理函数
信号处理数组int sig[32]。数组每个条目都指定了如何处理相应的信号,0表示默认,1表示忽略,其他非0值表示用户模式下预先安装的信号捕捉函数。
(5)安装信号捕捉函数
进程系统调用
修改选定信号编号的处理函数,SIGKILL(9)和SIGSTOP(19)除外。已安装的处理函数一定是以下形式用户空间中信号捕捉函数的入口:
1.执行已安装的信号捕捉函数之前,通常将信号设置为默认。为捕捉下次出现的相同信号,必须重新安装捕捉系统。
实例
点击查看代码
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<string.h>
void handler(int sig,siginfo_t *siginfo,void *context)
{
printf("handler:sif=%d from PID=%d UID=%d\n",sig,siginfo->si_pid,siginfo->si_uid);
}
int main(int argc,char *argv[])
{
struct sigaction act;
memset(&act,0,sizeof(act));
act.sa_sigaction = &handler;//添加响应函数
act.sa_flags = SA_SIGINFO;
sigaction(SIGTERM,&act,NULL);//将行为act放入响应处理机制
printf("proc PID=%d looping\n",getpid());
printf("enter kill PID to send SIGTERM signal to it\n");
while(1)//一直循环
{
sleep(10);
}
}
·函数调用和命令
-
6.4信号处理步骤
(1)当某进程处于内核模式是,会检查并处理未完成的信号。
(2)重置用户安装的信号捕捉器。
(3)信号和唤醒。
-
6.5信号与异常
Unix设计最初用途如下
-
6.7信号做为IPC
-
6.7 Linux中的IPC
进程之间通信的机制。 -
6.7.1管道和FIFO
-
6.7.2信号
-
6.7.3System V IPC
在POSIX标准下,包括共享内存、信号量和消息队列。 -
6.7.4 POSIX消息队列
类似于System V IPC的消息队列,更通用且具有移植性 -
6.7.5线程同步机制
Linux不区分进程和线程。在Linux中,进程共享某些公共资源的线程。如果是使用共享地址空间的clone()系统调用创建的线程,他们通过共享内存进行通信。 -
6.7.6 套接字
跨网络通信的的IPC机制。 -
6.8编程项目
点击查看代码
#include<stdio.h>
#include<signal.h>
#include<fcntl.h>
#include<string.h>
#define LEN 64
int ppipe[2];
int pid;
char line[LEN];
int parent()
{
printf("parent %d running \n",getpid());
close(ppipe[0]);
while(1)
{
printf("parent %d:input a line :\n",getpid());
fgets(line,LEN,stdin);
line[strlen(line)-1] = 0; // kill the \n at and
printf("parent %d write to pipe\n",getpid());
write(ppipe[1],line,LEN);
printf("printf %d send signal 10 to %d\n",getpid(),pid);
kill(pid,SIGUSR1);
}
}
void chandler(int sig)
{
printf("\nchild %d got an interrupt sig=%d\n",getpid(),sig);
read(ppipe[0],line,LEN);
printf("child %d get a message =%s\n",getpid(),line);
}
int child()
{
char msg[LEN];
int parent = getppid();
printf("child %d running \n",getpid());
close(ppipe[1]);
signal(SIGUSR1,chandler);
while(1);
}
int main()
{
pipe(ppipe);
pid = fork();
if(pid) parent();
else child();
}