UNIX环境高级编程读书笔记(十)—信号 (2)

二、不可靠信号安装和发送函数。

1.

名称::

signal

功能:

信号安装(设置信号关联动作)

头文件:

#include <signal.h>

函数原形:

typedef void (*sighandler_t)(int);

sighandler_t signal(int signum,sighandler_t handler);

参数:

signum  信号名

handler  操作方式

返回值:

成功则为以前的信号处理配置,若出错则为SIG_ERR

signum参数是信号名,handler的值是:1。常数SIG_IGN:表示忽略此信号。2。SIG_DFL:表示接到此信号后的动作是系统默认动作。3。函数地址:表示我们捕捉此信号,并且调用用户设置的信号处理程序。当调用signal设置信号处理程序时,第二个参数是指向该函数的指针。

 

/*10_1.c*/

  #include <stdio.h>

  #include <unistd.h>

  #include <signal.h>

  

  main(){

  signal(SIGINT,SIG_IGN);

  printf("hello!n");

  sleep(10);

  printf("hellon");

  }

上面的代码忽略了SININT信号.

此程序执行会在屏幕上先打印一个“hello!”,然后睡眠10分钟。在此期间用户按ctrl+c没有任何反应,因为signal函数已将SIGINT信号(按ctrl+c会产生)设为忽略。

然后看下面的程序:

 /*10_2.c*/

#include <stdio.h>

  #include <unistd.h>

  #include <signal.h>

  

  void catch(int sig);

  

  main(){

  signal(SIGINT,catch);

  printf("hello!n");

  sleep(10);

  printf("hello!n");

  }

  

  void catch(int sig){

  printf("catch signaln");

}

 

  当用户按下ctrl+c时,进程被中断,catch()被执行.中断处理函数处理完毕后,转回断点执行下面的指令.

  当编写自己的中断处理函数时,注意下面两点:

  1.信号不能打断系统调用.

2.信号不能打断信号处理函数.

 

2.

名称::

pause

功能:

等待信号

头文件:

#include <unistd.h>

函数原形:

int pause(void);

参数:

返回值:

-1,errno设置为EINTR

pause函数使调用进程挂起直至捕捉到一个信号,pause才返回。在这种情况下,pause返回-1,errno设置为EINTR..

下面是一个例子:

/*10_3.c*/

#include <signal.h>

 

static void sig_usr(int signo);

 

int main()

{

if(signal(SIGUSR1,sig_usr)==SIG_ERR)

    perror(SIGUSR1);

if(signal(SIGUSR2,sig_usr)==SIG_ERR)

    perror(SIGUSR2);

while(1)

    pause();

}

 

static void sig_usr(int signo)

{

if(signo==SIGUSR1)

    printf(“received SIGUSR1\n”);

else if(signo==SIGUSR2)

    printf(“received SIGUSR2\n”);

else

    printf(“received signal %d\n”,signo);

}

pause();函数使调用进程挂起,直至捕捉到一个信号。

 

下面我们来运行一下:

#./10_1 &                                          在后台运行进程

[3] 18864                                                

#.kill -USR1 18864                             向该进程发送SIGUSR1

received SIGUSR1

# kill –USR2 18864                      向该进程发送SIGUSR1

received SIGUSR2

# kill 18864                                        向该进程发送SIGTERM

[3]+ Terminated                   ./signal

 

可以看到当用户kill -USR1 18864的时候产生了SIGUSR1信号,signal 定义了处理此信号要调用sig_usr函数,所以就在屏幕上打印出received SIGUSR1。

       shell自动将后台进程对中断和退出信号的处理方式设置为忽略。于是当按中断键时就不会影响到后台进程。如果没有执行这样的处理,那么当按中断键时,它不但会终止前台进程,还会终止所以的后台进程。

       我们还应注意的是,我们不能在信号处理程序中调用某些函数,这些函数被称为不可重入函数,例如malloc,getpwnam..那是因为当发生中断的时候系统有可能正在执行这些函数,在中断中调用这些函数可能会覆盖原来的信息,因而产生错误。

 

3.

名称::

kill/raise

功能:

信号发送函数

头文件:

#include <signal.h>

函数原形:

int kill(pid_t pid,int signo);

int raise(int signo);

参数:

pid     进程id

signo   信号

返回值:

若成功返回0,若出错返回-1

kill函数将信号发送给进程或进程组。raise函数则允许进程向自己发送信号。

raise(signo)等价于kill(getpid(),signo);

kill的pid函数有4种不同的情况:

pid>0 将信号发送给进程ID为pid的进程。

pid==0将信号发送给与发送进程同一组的所有进程。

pid<0 将该信号发送给其进程组id等于pid绝对值。

pid==-1将信号发送给进程有权向它发送信号的系统上的所有进程。

       进程将信号发送给其他进程需要许可权。超级用户可将信号发送另一个进程。对于非超级用户,其基本规则是发送者的实际或有效用户ID必须等于接收者的实际或有效用户ID。

 

/*10_4.c*/

#include <signal.h>

#include <stdio.h>

 

void sig_usr(int);

 

main()

{

if(signal(SIGINT,sig_usr)==SIG_ERR)

    perror(“error”);

while(1);

}

 

void sig_usr(int signo)

{

if(signo==SIGINT)

    printf(“received SIGINT\n”);

kill(getpid(),SIGKILL);

}

程序运行后,当用户按ctrl+c后,程序调用信号处理函数输出received SIGINT,然后调用kill函数中止进程。此程序的kill(getpid(),SIGKILL);也可以写成raise(SIGKILL);.

你可能感兴趣的:(linux,读书笔记,apue)