Linux进程通信之信号通信

信号通信

信号通信很简单,将特定信号传递给进程,使进程进行相应动作,信号是软中断,只要执行过,就生效,不必一直卡死等待信号来临,以此达到通信的目的。linux信号量有很多在文章最后列举;


信号通信函数结构

#include <signal.h>  
void (*signal(int signo,void(*func)(int)))(int)  

可以看到信号函数结构比较复杂

  • signal:
    本身是个函数指针,
  • signal函数参数:
    • signo:
      具体信号名称或者编号
    • func:
      函数指针,指向信号处理函数,函数参数为int型
      不写函数一般采用下面两个宏代替
      SIG_IGN
      忽略此信号
      SIG_DFL
      按默认的方式处理此信号

信号通信小例程:

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

    void my_func(int sign_no)  
    {
        if(sign_no==SIGINT)  
            printf("I have get SIGINT\n");  
        else if(sign_no==SIGQUIT)  
            printf("I have get SIGQUIT\n");  
    }  
    int main()  
    {  
        printf("Waiting for signal SIGINT or SIGQUIT \n ");  

        /*注册信号处理函数*/  
        signal(SIGINT, my_func);  
        signal(SIGQUIT, my_func);  

        pause();  
        exit(0);  
    }  

在主函数中注册信号处理方式,这里没有采用两个宏处理,采用的是指定函数处理,注册完信号处理函数后,进程将会执行pause等待信号来临,特定信号出现,将会跳进信号处理函数func,结束进程。
试验方式是先将此进程跑起来,利用ps aux指令获取进程ID,采用kill命令向进程传递信号,观察进程运行状况,达到进程通信的目的。

    [root@localhost signal]# gcc -o mysignal mysignal.c   
    [root@localhost signal]# ls  
    mysignal  mysignal.c  
    [root@localhost signal]# ./mysignal   
    Waiting for signal SIGINT or SIGQUIT   

切换终端执行ps -aux

    root     27544  0.0  0.4  11592  3308 ?        Ss   21:03   0:04 sshd: root@pts/0   
    root     27548  0.0  0.2   6828  1696 pts/0    Ss+  21:03   0:00 -bash  
    root     28112  0.0  0.1   3840  1016 ?        S    22:51   0:00 /usr/libexec/hald-addon-rfkill-killswitch  
    root     28202  0.1  0.4  11592  3308 ?        Rs   23:02   0:00 sshd: root@pts/1   
    root     28206  0.0  0.2   6720  1584 pts/1    Ss   23:02   0:00 -bash  
    postfix  28232  0.0  0.3  13440  2468 ?        S    23:04   0:00 pickup -l -t fifo -u  
    root     28241  0.0  0.0   1848   352 tty2     S+   23:06   0:00 ./mysignal  
    root     28243  0.0  0.1   6532  1040 pts/1    R+   23:06   0:00 ps aux  

查看到进程编号28241,向进程发送信号。
[root@localhost ~]# kill -s SIGQUIT  28241  

另一终端查看进程运行情况:

    [root@localhost signal]# ./mysignal   
    Waiting for signal SIGINT or SIGQUIT   
     I have get SIGQUIT   
     [root@localhost signal]#   

可以看到进程接收到信号并执行相应动作。证明通信正常,这就是简单的信号通信。可以将信号注册函数中第二个参数改为SIG_IGN(忽略收到的信号),即便使进程接收到信号,进程也不会动作。将信号注册函数第二个参数改为SIG_DFL(按信号默认的方式处理),进程将会按信号特定的含义执行相应动作。这里不在演示。


信号让进程暂停的小例子

#include <stdio.h>
#include <signal.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
int main()
{
    int pid;
    pid=fork();
    if(pid==0)
    {
        signal(SIGCONT,SIG_DFL);
        while(1)
        {
            printf("I an son\n");
            sleep(2);
        }
    }else
    {
        sleep(10);
        kill(pid,SIGSTOP);
        sleep(20);
        kill(pid,SIGCONT);
        exit(0);
    }
    return 0;
}

信号列表

SIGHUP:本信号在用户终端结束时发出,通常是在终端的控制进程结束时,通知同一会话期内的各个作业,这时他们与控制终端不在关联。比如,登录linux时,系统会自动分配给登录用户一个控制终端,在这个终端运行的所有程序,包括前台和后台进程组,一般都属于同一个会话。当用户退出时,所有进程组都将收到该信号,这个信号的默认操作是终止进程。此外对于与终端脱离关系的守护进程,这个信号用于通知它重新读取配置文件。
SIGINT:程序终止信号。当用户按下CRTL+C时通知前台进程组终止进程。
SIGQUITCtrl+\控制,进程收到该信号退出时会产生core文件,类似于程序错误信号。
SIGILL:执行了非法指令。通常是因为可执行文件本身出现错误,或者数据段、堆栈溢出时也有可能产生这个信号。
SIGTRAP:由断点指令或其他陷进指令产生,由调试器使用。
SIGABRT:调用abort函数产生,将会使程序非正常结束。
SIGBUS:非法地址。包括内存地址对齐出错。比如访问一个4个字长的整数,但其地址不是4的倍数。它与SIGSEGV的区别在于后者是由于对合法地址的非法访问触发。
SIGFPE:发生致命的算术运算错误。
SIGKILL:用来立即结束程序的运行。
SIGUSR1:留给用户使用,用户可自定义。
SIGSEGV:访问未分配给用户的内存区。或操作没有权限的区域。
SIGUSR2:留给用户使用,用户可自定义。
SIGPIPE:管道破裂信号。当对一个读进程已经运行结束的管道执行写操作时产生。
SIGALRM:时钟定时信号。由alarm函数设定的时间终止时产生。
SIGTERM:程序结束信号。shell使用kill产生该信号,当结束不了该进程,尝试使用SIGKILL信号。
SIGSTKFLT:堆栈错误。
SIGCHLD:子进程结束,父进程会收到。如果子进程结束时父进程不等待或不处理该信号,子进程会变成僵尸进程。
SIGCONT:让一个停止的进程继续执行。
SIGSTOP:停止进程执行。暂停执行。
SIGTSTP:停止运行,可以被忽略。Ctrl+z
SIGTTIN:当后台进程需要从终端接收数据时,所有进程会收到该信号,暂停执行。
SIGTTOU:与SIGTTIN类似,但在写终端时产生。
SIGURG:套接字上出现紧急情况时产生。
SIGXCPU:超过CPU时间资源限制时产生的信号。
SIGXFSZ:当进程企图扩大文件以至于超过文件大小资源限制时产生。
SIGVTALRM:虚拟使用信号。计算的是进程占用CPU调用的时间。
SIGPROF:包括进程使用CPU的时间以及系统调用的时间。
SIGWINCH:窗口大小改变时。
SIGIO:文件描述符准备就绪,表示可以进行输入输出操作。
SIGPWR:电源失效信号。
SIGSYS:非法的系统调用。

猜你喜欢

转载自blog.csdn.net/z961968549/article/details/79987496