Chinaunix首页 | 论坛 | 博客
  • 博客访问: 403000
  • 博文数量: 59
  • 博客积分: 5195
  • 博客等级: 大校
  • 技术积分: 645
  • 用 户 组: 普通用户
  • 注册时间: 2006-12-01 14:38
文章分类

全部博文(59)

文章存档

2017年(1)

2011年(10)

2010年(1)

2009年(9)

2008年(1)

2007年(35)

2006年(2)

我的朋友

分类: LINUX

2009-05-08 13:21:31

关于信号的一些知识

一、信号
1、信号的基本概念
每个信号都对应一个正整数常量(称为signal number,即信号编号。定义在系统头文件中),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断。
信号与中断的相似点:
(1)采用了相同的异步通信方式;
(2)当检测出有信号或中断请求时,都暂停正在执行的程序而转去执行相应的处理程序;
(3)都在处理完毕后返回到原来的断点;
(4)对信号或中断都可进行屏蔽。
信号与中断的区别:
(1)中断有优先级,而信号没有优先级,所有的信号都是平等的;
(2)信号处理程序是在用户态下运行的,而中断处理程序是在核心态下运行;
(3)中断响应是及时的,而信号响应通常都有较大的时间延迟。
信号机制具有以下三方面的功能:
(1)发送信号。发送信号的程序用系统调用kill( )实现;
(2)预置对信号的处理方式。接收信号的程序用signal( )来实现对处理方式的预置;
(3)收受信号的进程按事先的规定完成对相应事件的处理。
2、信号的发送
信号的发送,是指由发送进程把信号送到指定进程的信号域的某一位上。如果目标进程正在一个可被中断的优先级上睡眠,核心便将它唤醒,发送进程就此结束。一个进程可能在其信号域中有多个位被置位,代表有多种类型的信号到达,但对于一类信号,进程却只能记住其中的某一个。
进程用kill( )向一个进程或一组进程发送一个信号。
3、对信号的处理
当一个进程要进入或退出一个低优先级睡眠状态时,或一个进程即将从核心态返回用户态时,核心都要检查该进程是否已收到软中断。当进程处于核心态时,即使收到软中断也不予理睬;只有当它返回到用户态后,才处理软中断信号。对软中断信号的处理分三种情况进行:
(1)如果进程收到的软中断是一个已决定要忽略的信号(function=1),进程不做任何处理便立即返回;
(2)进程收到软中断后便退出(function=0);
(3)执行用户设置的软中断处理程序。
二、所涉及的中断调用
1、kill( )
系统调用格式
int kill(pid,sig)
参数定义
int pid,sig;
其中,pid是一个或一组进程的标识符,参数sig是要发送的软中断信号。
(1)pid>0时,核心将信号发送给进程pid。
(2)pid=0时,核心将信号发送给与发送进程同组的所有进程。
(3)pid=-1时,核心将信号发送给所有用户标识符真正等于发送进程的有效用户标识号的进程。
2、killall( )
killall和kill发送的信号基本相同,它们的不同点是kill发送信号的对象是进程ID,killall发送信号的对象是进程名,如:
kill -USR1 1192
killall -USR1 firefox
3、signal( )
预置对信号的处理方式,允许调用进程控制软中断信号,如:
signal(SIGUSR1,信号处理函数);

singal函数的原型:
void (*signal(int   signo,void(*func)(int)))(int) 
这是Linux中的signal   interface   function,返回值类型:void(*sig....)
系统调用格式
signal(sig,function)
头文件为
#include
参数定义
signal(sig,function)
int sig;
void (*func) ( )
其中sig用于指定信号的类型,sig为0则表示没有收到任何信号,余者如下表:
值   名 字     说明
01 SIGHUP 挂起(hangup)
02 SIGINT 中断,当用户从键盘按ctrl+c键
03 SIGQUIT 退出,当用户从键盘按quit键时
04 SIGILL 非法指令
05 SIGTRAP 跟踪陷阱(trace trap),启动进程,跟踪代码的执行
06 SIGIOT IOT指令
07 SIGEMT EMT指令
08 SIGFPE 浮点运算溢出
09 SIGKILL 杀死、终止进程
10 SIGBUS 总线错误
11 SIGSEGV 段违例(segmentation? violation),进程试图去访问其虚地址空间以外的位置
12 SIGSYS 系统调用中参数错,如系统调用号非法
13 SIGPIPE 向某个非读管道中写入数据
14 SIGALRM 闹钟。当某进程希望在某时间后接收信号时发此信号
15 SIGTERM 软件终止(software? termination)
16 SIGUSR1 用户自定义信号1
17 SIGUSR2 用户自定义信号2
18 SIGCLD 某个子进程死
19 SIGPWR 电源故障
function:在该进程中的一个函数地址,在核心返回用户态时,它以软中断信号的序号作为参数调用该函数,对除了信号SIGKILL,SIGTRAP 和SIGPWR以外的信号,核心自动地重新设置软中断信号处理程序的值为SIG_DFL,一个进程不能捕获SIGKILL信号。
function 的解释如下:
(1)function=1时,进程对sig类信号不予理睬,亦即屏蔽了该类信号;
(2)function=0时,缺省值,进程在收到sig信号后应终止自己;
(3)function为非0,非1类整数时,function的值即作为信号处理程序的指针。

例如 :

#include
#include //alarm函数头文件
#include
int waite;
void start(){
   waite=0;
}
//自定义中断调用函数
static void waiting(){
   while(waite==1);
}
main(){
   int pid1,pid2;
      if(pid1>0){
           printf("chilld process 1 is %d\n",pid1);
           while((pid2=fork())==-1);
               if(pid2>0){
                    printf("child process 2 is %d\n",pid2);
                    printf("please press 'delete'\n");
                    waite=1;
                    if(signal(SIGUSR1,start)==SIG_ERR);
                    else{
                       alarm(5);
                       signal(SIGALRM,start);//alarm函数使用的信号
                   }
                  waiting();
                  kill(pid1,16);//向child 1 子进程发送16号中断
                  kill(pid2,17);//向child 2 子进程发送17号中断
                  wait(0);//等待两个子进程结束
                  wait(0);
                  printf("parent process is killed\n");
                  exit(0);
             }
             else{
                 waite=1;
                 signal(17,start);//接受父进程发送的17号中断,调用信号中断函数start()
                 waiting();
                 printf("child 2 is killed\n");
                 exit(0);
              }
         }
         else{
             waite=1;
             signal(16,start);//接受父进程发送的16号中断,调用信号中断函数start()
             waiting();
             printf("child 1 is killed\n");
             exit(0);
        }
}



捕捉退出的子进程:

sigaction函数实现:

struct sigaction child_action;

child_action.sa_sigaction = child_signal;
sigemptyset(&child_action.sa_mask);
child_action.sa_flags = SA_SIGINFO;
if (sigaction(SIGCHLD,&child_action,NULL) < 0)
    return;
   
sa_sigaction函数有三个参数,第一个参数是接收到的信号,第二个参数是一个指向struct siginfo结构的指针,具体情况可以看man手册,第三个参数没有使用。
如果使用sa_sigaction函数则sa_flags的值必须为SA_SIGINFO。
SA_SIGINFO的意思是:信号附带的参数可以传递到信号处理函数中。
SIGCHLD的意思是:当有子进程退出时会触发此信号。

信号处理函数实现:

void child_signal(int sig,siginfo_t *sig_info,void *unused)
{
    int ret;
   
    调用system函数时会生成一个子进程,这个子进程退出后也会调用这个信号处理函数,可以通过判断进行控制
    if (sig_info->si_pid != child_pid)
        return;
   
    do
    {
        ret = waitpid(child_pid,NULL,WNOHANG);
    }while (ret == 0);
   
    if (ret == child_pid)
    {
        子进程退出成功
    }
    else
    {
        子进程退出失败
    }
}

sig: 子进程退出时发出的信号,此处是17
sig_info->si_pid: 子进程的进程ID号
child_pid: 全局变量,在用fork生成子进程时将子进程ID号赋给它
阅读(7473) | 评论(0) | 转发(0) |
0

上一篇:shell记忆集合

下一篇:gtk国际化编程

给主人留下些什么吧!~~