Linux信号处理相关内容

Linux信号处理相关内容:

1.pid_t fork( void); 创建子进程
pid_t 是一个宏定义,其实质是int 被定义在#include<sys/types.h>中
返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间(读时共享,写时复制)
fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。

当fork()完后,到底是先执行子进程还是先执行父进程,不同的系统会存在不同的先后。

代码示例:循环创建子进程

//进程id数组 
pid_t pid[5]={0};

for(i=0;i<5;i++){
	iRet = fork();
	if(-1==iRet){
		perror("fork error:");
		//此处还可以将已将创建成功的子进程终止掉 kill(pid,SIGINT);
		exit (-1);
	}else if(0==iRet){
		//fork()返回值为0时,表示子进程
		//子进程直接退出循环,避免子进程再创建子进程
		break;
	}else if(iRet>0){
		//父进程fork()后,返回子进程的ID
		//保存子进程ID值,也可以再子进程中使用getpid()来获取
		pid[i]=iRet;
		continue;
	}
	if(5==i){  //当i=5时,则是父进程完成所有的子进程创建,并退出循环
		sleep(5); //目的,让所有子进程退出后,父进程才退出,可以使用其他方法,如waitpid等;
		printf("I'm parent,pid=%d\n", getpid());
		exit (0);
	}else{   //i值为[0-4],则对应的是第1-5个子进程
		sleep(i+1);   //对应的子进程sleep相应的i+1秒,可以使子进程顺序执行
		printf("I'm %dth child,pid=%d\n", i+1, getpid() );
		exit (0);
	}
	exit (0);
}
  1. int pause(void); 让进程暂停直到信号出现
    pause()会令当前的进程暂停(进入睡眠状态),直到被信号(signal)所中断
    返回值: 只返回-1
    程序涉及到pause处理流程:1.进程顺序执行,当遇到pause()时,进入休眠状态,不再向下执行,等到信号到来;2.当该进程收到信号(如:kill(pid,信号值)或命令行的信号等);3.该进程收到信号后,执行signal(信号值, 信号处理函数)定义的信号处理函数,进行处理,并成功返回;4.该进程的pause()才会返回,返回值为-1;

  2. int kill(pid_t pid,int signo);
    功能:向进程或进程组发送一个信号(成功返回 0; 否则,返回 -1 )
    参数:
    pid>0:发送给进程号为pid的进程
    pid=0:发送给当前进程所属进程组里的所有进程
    pid=-1:发送给除1号进程和自身以外的所有进程
    pid<-1:发送给属于进程组-pid的所有进程
    signo:发送的信号值
    signo = 0:不发送信号,可用于检查目标进程是否存在,以及当前进程是否具有向目标进程发送信号的权限(root权限的进程可以向任何进程发送信号,非root权限的进程只能向属于同一个session或者同一个用户的进程发送信号)。
    信号值可以使用命令: kill -l 查看 (对应的是信号宏名和值) (见文末)
    kill函数可以对进程发送signal();发送的信号,可以使用signal来进行捕捉。(除SIGKILL和SIGSTOP信号不能捕捉,也不能忽略)
    在linux里使用的Kill命令。实际上是对Kill()函数的一个包装
    如: kill( 1234, SIGKILL)函数等同于 kill -9 1234; 将1234进程杀掉

4.sig_t signal(int signum,sig_t handler); 设置某一信号的对应动作
参数:
1.signum指明了所要处理的信号类型,它可以取除了SIGKILL和SIGSTOP外的任何一种信号(原因该两种信号不能进行捕捉和忽略操作)。
2.handler描述了与信号关联的动作,它可以取以下三种值:
SIG_IGN:忽略信号,即使没有意义,代码执行仍将继续。
SIG_DFL:信号由该特定信号的默认动作处理。
无返回值的函数地址:此函数必须在signal()被调用前申明,handler中为这个函数的名字。当接收到一个类型为signum的信号时,就执行handler 所指定的函数。
这个函数应有如下形式的定义void func(int sig); 返回值为void 型 且只有一个int型的信号值参数

函数说明:
signal()会依参数signum 指定的信号编号来设置该信号的处理函数。当指定的信号到达时就会跳转到参数handler指定的函数执行。当一个信号的信号处理函数执行时,如果进程又接收到了该信号,该信号会自动被储存而不会中断信号处理函数的执行,直到信号处理函数执行完毕再重新调用相应的处理函数。但是如果在信号处理函数执行时进程收到了其它类型的信号,该函数的执行就会被中断。

//示例代码,顺便说明回调函数和注册函数

//自定义信号处理函数:void func (int);
//该函数是回调函数的定义
void sig_deal( int signo ){
	//进行对应信号的处理
	printf( "hello! signo=%d\n", signo );
	return;
}

//主程序中调用信号处理
//当该进程收到SIGINT信号时,调用sig_deal信号处理函数进行处理,且sig_deal函数自动传入SIGINT作为参数
signal( SIGINT, sig_deal );  //signal()函数叫注册函数;sig_deal叫回调函数

附一段小代码,执行理解该过程:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <signal.h>

//自定义信号处理函数(信号处理回调函数规定:返回void 型,参数只有一个,且是int型的信号值)
void sign_deal( int signo ){

    //仅仅作为接收信号,然后信号处理函数通过,然后pause()才返回
    printf( "signo = %d, sign_deal success\n", signo );
    return ;
}

int main(){

    int i = 0;
    int j = 0;
    int iRet = 0;
    pid_t cpid[5];

    for( i =0; i<5; i++ ){
         cpid[i]=0;
    }

    i = 0;
    printf( "test for loop \n" );
    for( j = 0; j < i; j++ ){
         //第一次:先执行j=0;再判断j<i;然后条件成功再执行循环体内容
         printf( "i=%d;j=%d", i, j );
    }
    printf( "test for loop end\n" );

    signal( SIGUSR1, sign_deal );

    //循环创建5个子进程
    for( i = 0; i < 5; i++ ){
         iRet = fork();
         if( iRet < 0 ){
             perror( "fork error:" );
             for( j = 0; j < i; j++ ){ //结束已经创建的子进程
                  kill( cpid[j], SIGINT );
             }
             exit (-1);
         }else if( iRet == 0 ){   //子进程返回
             break;
         }
         //父进程返回 > 0
         cpid[i] = iRet;
         continue;
    }

    /*先将子进程暂停pause(),然后父进程发送信号给子进程kill(),使其继续运行*/
    if( i == 5 ){
        //父进程创建5个子进程后,循环退出
        //1.先让子进程执行,然后子进程pause()暂停,等待信号
        sleep( 6 );
        printf( "I am parent,pid = %d\n", getpid() );

        //2.给子进程发送SIGUSR1信号,让子进程调用信号处理函数,并完成pause的返回
        for( i = 0; i < 5; i++ ){
             sleep( 1 );
             kill( cpid[i], SIGUSR1 );
        }

        exit ( 0 );
    }

	//此处分开区分子进程,可以每个子进程执行各自的操作
    if( 0 == i ){  //子进程fork()==0,则break循环
        sleep(i+1);
        printf( "I am %d child,pid = %d\n", i+1, getpid() );
        pause();
        printf( "%dth child, pause after\n", i+1 );
        exit( 0 );
    } else if( 1 == i ){
        sleep(i+1);
        printf( "I am %d child,pid = %d\n", i+1, getpid() );
        pause();
        printf( "%dth child, pause after\n", i+1 );
        exit( 0 );
    } else if( 2 == i ){
        sleep(i+1);
        printf( "I am %d child,pid = %d\n", i+1, getpid() );
        pause();
        printf( "%dth child, pause after\n", i+1 );
        exit( 0 );
    } else if( 3 == i ){
        sleep(i+1);
        printf( "I am %d child,pid = %d\n", i+1, getpid() );
        pause();
        printf( "%dth child, pause after\n", i+1 );
        exit( 0 );
    } else if( 4 == i ){
        sleep(i+1);
        printf( "I am %d child,pid = %d\n", i+1, getpid() );
        pause();
        printf( "%dth child, pause after\n", i+1 );
        exit( 0 );
    }

    exit (0);
}

PS:
Linux系统中常用信号:
(1)SIGHUP:用户从终端注销,所有已启动进程都将收到该进程。系统缺省状态下对该信号的处理是终止进程。
(2)SIGINT:程序终止信号。程序运行过程中,按Ctrl+C键将产生该信号。
(3)SIGQUIT:程序退出信号。程序运行过程中,按Ctrl+\键将产生该信号。
(4)SIGBUS和SIGSEGV:进程访问非法地址。
(5)SIGFPE:运算中出现致命错误,如除零操作、数据溢出等。
(6)SIGKILL:用户终止进程执行信号。shell下执行kill -9发送该信号。
(7)SIGTERM:结束进程信号。shell下执行kill 进程pid发送该信号。
(8)SIGALRM:定时器信号。
(9)SIGCLD:子进程退出信号。如果其父进程没有忽略该信号也没有处理该信号,则子进程退出后将形成僵尸进程。
(10) USR1: 被用来告知应用程序重载配置文件

剩余的信号值说明:Linux signal 信号列表

=============================
后续补父进程等待子进程相关函数内容和signal和sigset的区别

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值