本节主要学习信号和与信号相关的处理函数,兴许还会更新。

http://blog.csdn.net/xiaoliangsky/article/details/40264151

一 信号

信号是UNIX和Linux系统响应某些条件而产生的一个事件。接收到该信号的进程会对应地採取一些行动。通常信号是由一个错误产生的。但它们还能够作为进程间通信或改动行为的一种方式。明白地由一个进程发送给还有一个进程。一个信号的产生叫生成。接收到一个信号叫捕获。

二 信号的种类

Signal         Description

SIGABRT   由调用abort函数产生。进程非正常退出

SIGALRM   用alarm函数设置的timer超时或setitimer函数设置的interval timer超时

SIGBUS    某种特定的硬件异常,通常由内存訪问引起

SIGCANCEL 由Solaris Thread Library内部使用。通常不会使用

SIGCHLD   进程Terminate或Stop的时候,SIGCHLD会发送给它的父进程。缺省情况下该Signal会被忽略

SIGCONT   当被stop的进程恢复执行的时候,自己主动发送

SIGEMT    和实现相关的硬件异常

SIGFPE    数学相关的异常。如被0除,浮点溢出。等等

SIGFREEZE Solaris专用。Hiberate或者Suspended时候发送

SIGHUP    发送给具有Terminal的Controlling Process,当terminal被disconnect时候发送

SIGILL    非法指令异常

SIGINFO   BSD signal。由Status Key产生,一般是CTRL+T。发送给全部Foreground Group的进程

SIGINT    由Interrupt Key产生,一般是CTRL+C或者DELETE。发送给全部ForeGround Group的进程

SIGIO     异步IO事件

SIGIOT    实现相关的硬件异常,一般相应SIGABRT

SIGKILL   无法处理和忽略。中止某个进程

SIGLWP    由Solaris Thread Libray内部使用

SIGPIPE   在reader中止之后写Pipe的时候发送

SIGPOLL   当某个事件发送给Pollable Device的时候发送

SIGPROF   Setitimer指定的Profiling Interval Timer所产生

SIGPWR    和系统相关。和UPS相关。

SIGQUIT   输入Quit Key的时候(CTRL+/)发送给全部Foreground Group的进程

SIGSEGV   非法内存訪问

SIGSTKFLT Linux专用,数学协处理器的栈异常

SIGSTOP   中止进程。

无法处理和忽略。

SIGSYS    非法系统调用

SIGTERM   请求中止进程,kill命令缺省发送

SIGTHAW   Solaris专用,从Suspend恢复时候发送

SIGTRAP   实现相关的硬件异常。通常是调试异常

SIGTSTP   Suspend Key。通常是Ctrl+Z。发送给全部Foreground Group的进程

SIGTTIN   当Background Group的进程尝试读取Terminal的时候发送

SIGTTOU   当Background Group的进程尝试写Terminal的时候发送

SIGURG    当out-of-band data接收的时候可能发送

SIGUSR1   用户自己定义signal 1

SIGUSR2   用户自己定义signal 2

SIGVTALRM setitimer函数设置的Virtual Interval Timer超时的时候

SIGWAITING Solaris Thread Library内部实现专用

SIGWINCH  当Terminal的窗体大小改变的时候。发送给Foreground Group的全部进程

SIGXCPU   当CPU时间限制超时的时候

SIGXFSZ   进程超过文件限制大小

SIGXRES   Solaris专用,进程超过资源限制的时候发送

三 信号相关的函数

1 signal函数

void (*signal(int sig, void (*func)(int)))(int);

signal是一个带有sig和func两个參数的函数,func是一个类型为void (*)(int)的函数指针。该函数返回一个与func同样类型的指针。指向先前指定信号处理函数的函数指针。准备捕获的信号的參数由sig给出,接收到的指定信号后要调用的函数由參数func给出。事实上这个函数的使用是相当简单的,通过以下的样例就能够知道。注意信号处理函数的原型必须为void func(int),或者是以下的特殊值:

    SIG_IGN:忽略信号

    SIG_DFL:恢复信号的默认行为

这个函数经常能够用以下要将的sigaction函数替代。



2 sigaction

int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);

该函数与signal函数一样,用于设置与信号sig关联的动作,而oact假设不是空指针的话。就用它来保存原先对该信号的动作的位置,act则用于设置指定信号的动作。



參数结构体sigaction定义例如以下:

struct sigaction{

    void       (*sa_handler)(int);

    void       (*sa_sigaction)(int, siginfo_t*, void*);

    sigset_t   sa_mask;

    int        sa_flags;

    void       (*sa_restorer)(void);

};



信号集sigset_t结构体:

typedef struct

{

    unsigned long sig[_NSIG_WORDS];

}sigset_t;



信号处理函数能够採用void (*sa_handler)(int)或void (*sa_sigaction)(int, siginfo_t *, void *)。究竟採用哪个要看sa_flags中是否设置了SA_SIGINFO位。假设设置了就採用void (*sa_sigaction)(int, siginfo_t *, void *)。此时能够向处理函数发送附加信息;默认情况下採用void (*sa_handler)(int),此时仅仅能向处理函数发送信号的数值。

sa_handler    此參数和signal()的參数handler同样。代表新的信号处理函数,其它意义请參考signal()。

sa_mask       用来设置在处理该信号时临时将sa_mask指定的信号集搁置。

sa_restorer   此參数没有使用。

sa_flags      用来设置信号处理的其它相关操作,下列的数值可用:

sa_flags      还能够设置其它标志:

SA_RESETHAND  当调用信号处理函数时,将信号的处理函数重置为缺省值SIG_DFL

SA_RESTART    假设信号中断了进程的某个系统调用,则系统自己主动启动该系统调用

SA_NODEFER    普通情况下, 当信号处理函数执行时。内核将堵塞该给定信号。可是假设设置了 SA_NODEFER标记, 那么在该信号处理函数执行时,内核将不会堵塞该信号。



返回值

运行成功则返回0,假设有错误则返回-1。

错误代码

EINVAL 參数signum 不合法, 或是企图拦截SIGKILL/SIGSTOPSIGKILL信号

EFAULT 參数act,oldact指针地址无法存取。

EINTR  此调用被中断



以下一个简单的样例,程序里面的sigemptyset、kill函数会在后面讲

action.c实例代码:

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <signal.h> void sig_handler(int sig)
{
switch(sig)
{
case 23:
printf("child : the signo is 23, hehe\n");
return;
case 22:
printf("father : hello wordl 22!\n");
return;
}
} int main()
{
struct sigaction act, oact;
int status; sigemptyset(&act.sa_mask);
act.sa_flags = 0;
act.sa_handler = sig_handler;
sigaction(23, &act, &oact);
sigaction(22, &act, &oact); pid_t pid, ppid; if (!(pid = fork()))
{
printf("child begin\n"); kill(getppid(), 22);
sleep(3); printf("child over\n");
}
else
{
printf("father begin\n"); kill(getpid(), 23); wait(&status); if (WIFSIGNALED(status))
{
printf("child process receive siganl %d\n", WTERMSIG(status));
} printf("father over\n");
} return 0;
}

3 sigaddset sigdelset

int sigaddset(sigset_t *set, int signum);

sigaddset()用来将參数signum 代表的信号增加至參数set 信号集里。

返回值

运行成功则返回0,假设有错误则返回-1。

错误代码

EFAULT 參数set指针地址无法存取

EINVAL 參数signum非合法的信号编号



int sigdelset(sigset_t *set, int signum)

sigdelset()用来将參数signum代表的信号从參数set信号集里删除。

返回值

运行成功则返回0

假设有错误则返回-1。

错误代码

EFAULT 參数set指针地址无法存取

EINVAL 參数signum非合法的信号编号



4 sigemptyset sigfillset

int sigemptyset(sigset_t *set);

sigemptyset()用来将參数set信号集初始化并清空。

返回值

运行成功返回0;

失败返回-1。

错误代码

EFAULT 參数set指针地址无法存取



int sigfillset(sigset_t * set);

sigfillset()用来将參数set信号集初始化。然后把全部的信号增加到此信号集里。

返回值

运行成功返回0。

失败返回-1。

错误代码

EFAULT 參数set指针地址无法存取



5 sigismember

int sigismember(const sigset_t *set,int signum);

sigismember()用来測试參数signum 代表的信号是否已增加至參数set信号集里。假设信号集里已有该信号则返回1,否则返回0。

返回值

信号集已有该信号则返回1。

没有则返回0;

假设有错误则返回-1。

错误代码

EFAULT 參数set指针地址无法存取

EINVAL 參数signum 非合法的信号编号



6 sigpending

int sigpending(sigset_t *set);

sigpending()会将被搁置的信号集合由參数set指针返回

返回值执

行成功则返回0。

假设有错误则返回-1。

错误代码

EFAULT 參数set指针地址无法存取

EINTR  此调用被中断。



7 sigprocmask

int sigprocmask(int how, const sigset_t *set, sigset_t *oldset);

一个进程的信号屏蔽字规定了当前堵塞而不能传送给该进程的信号集。sigprocmask()能够用来检測或改变眼下的信号屏蔽字,其操作參数how来决定,假设參数oldset不是NULL指针,那么当前的信号屏蔽字会由此指针返回。假设set是一个非空指针,则參数how指示怎样改动当前信号屏蔽字。每一个进程都有一个用来描写叙述哪些信号递送到进程时将被堵塞的信号集。该信号集中的全部信号在传送到进程后都将被堵塞。

參数how:

SIG_BLOCK:该进程新的信号屏蔽字是其当前信号屏蔽字和set指向信号集的并集,set包括了我们希望堵塞的附件信号。

SIG_UNBLOCK:该进程新的信号集屏蔽字是其当前信号屏蔽字和set所指向信号集的补集的交集。

set包括了我们希望解除堵塞的信号。

SIG_SETMASK:该进程新的信号屏蔽是set指向的值。

注意:

1)除SIG_SETMASK外,假设set是个空指针。则不改变该进程的信号屏蔽字,这时how的值也没有意义。

2)SIG_SETMASK与set空指针结合使用。即清空全部屏蔽的信号。

返回值:

运行成功返回0;

失败返回-1。

错误码

EFAULT:參数set、oldsset指针地址无法获取

EINTR:此调用被中断



以下是一个測试样例,測试被屏蔽的信号:

sigprocmask.c的实例代码:

http://blog.csdn.net/xiaoliangsky/article/details/40264151

////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////////////////////////
#include <stdio.h>
#include <stdlib.h>
#include <signal.h> void sig_handler(int signum)
{
switch(signum)
{
case SIGINT:
printf("the signo is SIGINT %d received, hehe\n", SIGINT);
return;
case SIGCHLD:
printf("the signo is SIGCHLD %d received, hihi!\n", SIGCHLD);
return;
case SIGUSR1:
printf("the signo is SIGUSR1 %d received, hihi!\n", SIGUSR1);
return;
case SIGIO:
printf("the signo is SIGIO %d received, hihi!\n", SIGIO);
return;
case SIGALRM:
printf("the signo is SIGALRM %d received, hihi!\n", SIGALRM);
return;
default:
printf("the signo %d is not processed\n", signum);
return;
}
} int main()
{
int i;
int status;
pid_t pid;
sigset_t set;
sigset_t oldset;
struct sigaction act;
struct sigaction oldact; act.sa_flags = 0;
act.sa_handler = sig_handler;
sigemptyset(&act.sa_mask);
sigaction(SIGINT, &act, &oldact);
sigaction(SIGCHLD, &act, &oldact);
sigaction(SIGUSR1, &act, &oldact);
sigaction(SIGALRM, &act, &oldact);
sigaction(SIGIO, &act, &oldact); sigemptyset(&set);
sigaddset(&set, SIGINT);
sigaddset(&set, SIGUSR1); if ((pid = fork()) < 0)
{
fprintf(stdout, "fork error\n");
exit(-1);
}
else if (pid > 0)
{
if (sigprocmask(SIG_BLOCK, &set, &oldset) < 0)//屏蔽信SINGINT、SIGUSR1
{
fprintf(stdout, "sigprocmask error\n");
kill(pid, SIGKILL);
exit(-1);
}
/*
waitpid(pid, &status, 0); if (WIFSIGNALED(status))
{
printf("child process receive siganl %d\n", WTERMSIG(status));
}
*/
pause();//接收SIGIO?
pause();//接收SIGALRM?
pause();//接收SIGCHLD? //pause();
//pause();
}
else
{
sleep(1);
kill(getppid(), SIGINT);//信号被屏蔽
sleep(1);
kill(getppid(), SIGIO);
sleep(1);
kill(getppid(), SIGUSR1);//信号被屏蔽
sleep(1);
kill(getppid(), SIGALRM);
sleep(2);
//子进程退出会发送一个SIGCHLD信号
} return 0;
}

8 sigsuspend

int sigsuspend(const sigset_t *mask);

函数sigsuspend将进程的信号屏蔽码设置为mask,然后与pause()函数一样等待信号的发生并运行完信号处理函数。信号处理函数运行完后再把进程的信号屏蔽码设置为原来的屏蔽字,然后sigsuspend函数才返回。

返回值

sigsuspend总是返回-1

以下是一个sigsuspend的样例:

sigsuspend的实例代码:

#include <unistd.h>
#include <signal.h>
#include <stdio.h> void sig_handler(int sig)
{
    if (sig == SIGINT)
printf("SIGINT sig\n");
else if (sig == SIGQUIT)
printf("SIGQUIT sig\n");
else if (sig == SIGUSR1)
printf("SIGUSR1 sig\n");
else if (sig == SIGUSR2)
printf("SIGUSR2 sig\n");
else
printf("SIGCHLD sig\n");
} int main()
{
    int i;
sigset_t new;
    sigset_t old;
    sigset_t wait;
struct sigaction act; act.sa_handler = sig_handler;
    act.sa_flags = 0; sigemptyset(&act.sa_mask);
sigaction(SIGINT, &act, 0);
sigaction(SIGQUIT, &act, 0);
sigaction(SIGUSR1, &act, 0);
    sigaction(SIGUSR2, &act, 0);
    sigaction(SIGCHLD, &act, 0); sigemptyset(&new);
sigaddset(&new, SIGINT); sigemptyset(&wait);
sigaddset(&wait, SIGUSR1);
    sigaddset(&wait, SIGUSR2); sigprocmask(SIG_BLOCK, &new, &old);     for (i=0; i < 90; ++i)
    {
        printf("%d\n", i);
sleep(1);
    } sigsuspend(&wait); printf("After sigsuspend\n");     printf("yyyy\n");
if (-1 == sigprocmask(SIG_SETMASK, &old, NULL))
{
perror("sigprocmask");
exit(-1);
}
    for (i=0; i < 30; ++i)
    {
printf("%d\n", i);
sleep(1);
    }
    printf("xxxxx\n"); return 0;
}

linux进程通信之信号的更多相关文章

  1. Linux 进程通信之 ——信号和信号量总结

    如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存.       所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...

  2. linux 进程通信之 信号

    一,管道PIPE 二,FIFO通信 三,mmap通信 四,信号的概念 信号的特点:简单,但不能携带大量的信息,满足特定条件就会发生 信号的机制:进程B发送信号给进程A.信号是由内核来处理的. 信号的产 ...

  3. Linux进程通信----匿名管道

    Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...

  4. linux进程通信

    e14: 进程间通信(进程之间发送/接收字符串/结构体): 传统的通信方式: 管道(有名管道 fifo,无名管道 pipe) 信号 signal System V(基于IPC的对象):         ...

  5. Linux进程通信学习总结

    http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念   引用标识符:引用标识符是一个整数,表示每一个SYSV ...

  6. Linux进程通信的几种方式总结

    进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...

  7. Python网络编程(进程通信、信号、线程锁、多线程)

    什么是进程通讯的信号? 用过Windows的我们都知道,当我们无法正常结束一个程序时, 可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢? 同样的功能在Linux上是通过生成信号和捕获信号来实 ...

  8. linux进程通信之管道

    1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...

  9. linux 进程通信之 共享内存

    共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...

随机推荐

  1. 【HTTP】Fiddler(二) - 使用Fiddler做抓包分析

    上文( http://blog.csdn.net/ohmygirl/article/details/17846199 )中已经介绍了Fiddler的原理和软件界面.本文主要针对Fiddler的抓包处理 ...

  2. OpenRisc-35-基于orpsoc,eCos的sd card controller的测试实验

    引言 之前,曾经在orpsoc的平台上,测试验证过其sd card controller的linux的驱动,但是并不是很完美,经过努力,终于在eCos下完成了其全部功能的验证,包括驱动层验证,文件系统 ...

  3. HDU 1593 find a way to escape

    数学题. 题意是问你能不能逃脱. 当V1的 角速度大于 V2的时候,能够一直保持 V1,O(圆心),V2 三点一线. 跑到一定距离.角速度小于的时候,就以三点一线为初始状态直接跑直线. #includ ...

  4. C语言中的enum(枚举)使用方法

    近期在写数据结构的广义表时候用到了这个概念,在学习C语言的时候没有太注意们这里学一下. 我在网上结合了非常多资料,这里自己总结一下. 首先说.JAVA和C++中都有枚举类型. 假设一个变量你须要几种可 ...

  5. MSSQL - 多表查询

    SELECT u.UserNumber, u.UserName, c.CarNumber, c.CarName, c.CarEngine, s.BuyLs, s.BuyTime FROM Tb_Sal ...

  6. Eclipse用法和技巧二:自动生成Main方法1

    刚开始编写java小程序,基本都要用到main方法.后期开发大一点的程序,也可以用main方法进行单元测试.总是编写main方法,感觉太无聊了,幸好Eclipse可以帮我们自动生成main方法.见图: ...

  7. TODO管理工具TaskWarrior (跨平台C++代码)

    Taskwarrior 是一个基于命令行的 TODO 列表管理工具.主要功能包括:标签.彩色表格输出.报表和图形.大量的命令.底层API.多用户文件锁等功能. http://www.oschina.n ...

  8. hadoop学习;hadoop伪分布搭建

    先前已经做了准备工作安装jdk什么的,以下開始ssh免password登陆.这里我们用的是PieTTY工具,当然你也能够直接在linux下直接操作 ssh(secure shell),运行命令 ssh ...

  9. Ubuntu 无法拖拽复制

    首先确定 在ubuntu 下,vmware tools 已经安装成功 有些时候会出现vmware tools 已经安装成功,但是却无法实现拖拽和复制 1.首先在虚拟机设置里面勾选共享剪切板 2.然后重 ...

  10. Hadoop大数据零基础高端实战培训系列配文本挖掘项目