linux进程通信之信号
本节主要学习信号和与信号相关的处理函数,兴许还会更新。
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进程通信之信号的更多相关文章
- Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存. 所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...
- linux 进程通信之 信号
一,管道PIPE 二,FIFO通信 三,mmap通信 四,信号的概念 信号的特点:简单,但不能携带大量的信息,满足特定条件就会发生 信号的机制:进程B发送信号给进程A.信号是由内核来处理的. 信号的产 ...
- Linux进程通信----匿名管道
Linux进程通信中最为简单的方式是匿名管道 匿名管道的创建需要用到pipe函数,pipe函数参数为一个数组表示的文件描述字.这个数组有两个文件描 述字,第一个是用于读数据的文件描述符第二个是用于写数 ...
- linux进程通信
e14: 进程间通信(进程之间发送/接收字符串/结构体): 传统的通信方式: 管道(有名管道 fifo,无名管道 pipe) 信号 signal System V(基于IPC的对象): ...
- Linux进程通信学习总结
http://blog.csdn.net/xiaoweibeibei/article/details/6552498 SYSV子系统的相关概念 引用标识符:引用标识符是一个整数,表示每一个SYSV ...
- Linux进程通信的几种方式总结
进程通信的目的 数据传输 一个进程需要将它的数据发送给另一个进程,发送的数据量在一个字节到几M字节之间 共享数据 多个进程想要操作共享数据,一个进程对共享数据 通知事 一个进程需要向另一个或一组进程发 ...
- Python网络编程(进程通信、信号、线程锁、多线程)
什么是进程通讯的信号? 用过Windows的我们都知道,当我们无法正常结束一个程序时, 可以用任务管理器强制结束这个进程,但这其实是怎么实现的呢? 同样的功能在Linux上是通过生成信号和捕获信号来实 ...
- linux进程通信之管道
1.介绍: 1)同一主机: unix进程通信方式:无名管道,有名管道,信号 system v方式:信号量,消息队列,共享内存 2)网络通信:Socket,RPC 2.管道: 无名管道(PIPE):使用 ...
- linux 进程通信之 共享内存
共享内存是被多个进程共享的一部分物理内存.共享内存是进程间共享数据的一种最快的方法.一个进程向共享内存区域写入了数据,共享这个内存区域的全部进程就能够立马看到当中的内容. 关于共享内存使用的API k ...
随机推荐
- VMware machine里的文件
.nvram——虚拟机BIOS或EFI配置文件. .vmdk——虚拟磁盘特性文件,是存放虚拟磁盘当前状况和上次执行快照时的状况之间的差异的快照文件. .vmsd——虚拟机快照,包含虚拟机快照信息的数据 ...
- 基于visual Studio2013解决面试题之1204大数组查找
题目
- iOS开发 - 应用内打开第三方应用并传值
首先说下这个功能, 应该都有接触过. 比方,你下载了一个电子书,然后选择打开方式的时候,可能会看到你手机中已经安装的阅读类App. 或者,你的QQ收到了某个文件,你也能够选择本地的应用来打开. 那这种 ...
- js关键字与保留字的坑。
在写一个算法,迷宫出口的算法,作为一个有追求的前端,首先在解决算法的问题之前要把迷宫的图做的漂漂亮亮的才对得住自己的审美,所以我花了一个钟的时间去写这个地图. 不过这次我们说的并不是迷宫的解法,也不是 ...
- 编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功)
编译mapnik(win7 环境下vs2008编译mapnik 0.7.1 成功) ------by wangsh 2012.02.22 Mapnik 是一个开源的 Python/C++ 地图渲染引 ...
- Last_IO_Errno: 1236 Last_IO_Error: Got fatal error 1236 from master when reading data from binary lo
mysql> show slave status\G *************************** 1. row *************************** ...
- Linux内核驱动将多个C文件编译成一个ko文件的方法——每一个C文件中都有module_init与module_exit
以两个C文件为例: 将本该被分别编译成adc_device.ko和adc_driver.ko的adc_device.c.adc_driver.c编译成一个ko文件! 採用方法: 第一步.改动C文件 1 ...
- poj 2126 Factoring a Polynomial 数学多项式分解
题意: 给一个多项式,求它在实数域内的可分解性. 分析: 代数基本定理. 代码: //poj 2126 //sep9 #include <iostream> using namespace ...
- 进阶-案例九: WD中实现export 到Excel,Doc,Txt.
1.导出excel 文件代码 导出事件代码: METHOD onactionimport . *导出excel: DATA: lo_node TYPE REF TO if_wd_context_nod ...
- (step6.3.3)hdu 1150(Machine Schedule——二分图的最小点覆盖数)
题目大意:第一行输入3个整数n,m,k.分别表示女生数(A机器数),男生数(B机器数),以及它们之间可能的组合(任务数). 在接下来的k行中,每行有3个整数c,a,b.表示任务c可以有机器A的a状态或 ...