Linux 信号通信
发送信号 kill -信号id pid
- kill -9 1234
所有信号
1 ~ 31的信号为传统UNIX支持的信号,是不可靠信号(非实时的) 不可排队
32 ~ 63的信号是后来扩充的,称做可靠信号(实时信号) 可排队
信号 | 信号ID | 含义 | 是否可捕获 |
---|---|---|---|
SIGHUP | 1 | 本信号在用户终端连接(正常或非正常)结束时发出 | YES |
SIGINT | 2 | 程序终止(interrupt)信号, 在用户键入INTR字符(通常是Ctrl-C)时发出,用于通知前台进程组终止进程 | |
SIGQUIT | 3 | 和SIGINT类似, 但由QUIT字符(通常是Ctrl-/)来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信号 | |
SIGILL | 4 | 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号 | |
SIGTRAP | 5 | 由断点指令或其它trap指令产生. 由debugger使用 | |
SIGABRT | 6 | 调用abort函数生成的信号:abort()是使异常程序终止 | |
SIGBUS | 7 | 非法地址, 包括内存地址对齐(alignment)出错 | |
SIGFPE | 8 | 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢出及除数为0等其它所有的算术的错误 | |
SIGKILL | 9 | 用来立即结束程序的运行. 本信号不能被阻塞、处理和忽略 | NO |
SIGUSR1 | 10 | 留给用户使用 | |
SIGSEGV | 11 | 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据 | |
SIGUSR2 | 12 | 留给用户使用 | |
SIGPIPE | 13 | 管道破裂。这个信号通常在进程间通信产生,比如采用FIFO(管道)通信的两个进程,读管道没打开或者意外终止就往管道写,写进程会收到SIGPIPE信号 | |
SIGALRM | 14 | 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号 | |
SIGTERM | 15 | 程序结束(terminate)信号, 与SIGKILL不同的是该信号可以被阻塞和处理 | yes |
SIGCHLD | 17 | 子进程结束时, 父进程会收到这个信号 | |
SIGCONT | 18 | 让一个停止(stopped)的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符 | NO |
SIGSTOP | 19 | 停止(stopped)进程的执行. 注意它和terminate以及interrupt的区别:该进程还未结束, 只是暂停执行 | NO |
SIGTSTP | 20 | 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时(通常是Ctrl-Z)发出这个信号 | YES |
SIGTTIN | 21 | 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN信号. 缺省时这些进程会停止执行 | |
SIGTTOU | 22 | 类似于SIGTTIN, 但在写终端(或修改终端模式)时收到 | |
SIGURG | 23 | 有”紧急”数据或out-of-band数据到达socket时产生 | |
SIGXCPU | 24 | 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/改变 | |
SIGXFSZ | 25 | 当进程企图扩大文件以至于超过文件大小资源限制 | |
SIGVTALRM | 26 | 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间 | |
SIGPROF | 27 | 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的时间 | |
SIGWINCH | 28 | 窗口大小改变时发出 | |
SIGIO | 29 | 文件描述符准备就绪, 可以开始进行输入/输出操作. | |
SIGPWR | 30 | Power failure | |
SIGSYS | 31 | 非法的系统调用 |
重要消息
- SIGINT 2
- SIGKILL 9
信号的基本操作
- 发送信号
- 安装中断
- 递送信号
- 捕获信号
- 屏蔽信号
Kill() 发送信号函数
给指定 pid发送信号
int kill(pid,signum);
- pid : pid>0 给pid发送信号 |
pid = 0 发送给当前pid组的所有进程
pid = -1发送给所有进程
pid < 0 发送给 绝对值PID所对应的组上
sigqueue() 发送信号函数
int sigqueue(pid_t pid, int sig, const union sigval value);
可带信息发送 信号
- 头文件 #include
- pid: 要发送给的PID
- sig: 发送什么信号
- value:发送 额外的 sigval 参数
pid_t pid = atoi(args[1]);
union sigval v;
v.sival_int = 100;
sigqueue(pid,SIGINT,v);
~~~~~~~~~~~~~~~~~~~~~~~
union sigval {
int sival_int;
void *sival_ptr;
};
signal() 绑定信号函数
设置某一信号的对应动作 功能比较少 推荐使用 sigaction() 函数
sighandler_t signal(int signum, sighandler_t handler);
头文件 #include
signum : 指明了所要处理的信号类型
handler : 处理的方式(是系统默认还是忽略还是捕获)也可以是指定函数
**SIG_IGN 表示忽略该信号**
SIG_DFL 表示恢复对信号的系统默认处理
int myfunc(int sig) //参数只有一个 信号值
{
printf("%d",sig);
}
signal(SIGINT,myfunc); //当收到SIGINT消息用myfunc 函数来处理
getpid() 获取当前进程的PID
pid_t getpid(void);
- 头文件 #include
getgpid 获取当前进程的组PID
pid_t getgpid(void);
- 头文件 #include
可发送 信号的函数
raise() 给自己发信号
int raise(int sig);
- 头文件 #include
- sig:要发送的信号
alarm() 定时函数 一次性
unsigned int alarm(unsigned int seconds);
从当前时间后 几秒 发送 SIGALRM 信号 一次性的
如果没有去捕捉 SIGALRM 信号就会调用系统默认的 处理函数 会退出程序
头文件 #include
seconds:定时时间 / 秒
signal(SIGALRM,fun); //给 SIGALRM信号绑定 fun函数
alarm(2); // 2 秒后 发送 SIGALRM信号
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
{
alarm(3);
alarm(2); //会覆盖之前设置的 3 秒 并且返回上一次设置的剩余时间
alarm(1);
}
ualarm() 定时函数 多次发送
useconds_t ualarm(useconds_t usecs, useconds_t interval);
在 usecs 时会发送 SIGALRM 信号 并且在 interval 后再次发送
如果没有去捕捉 SIGALRM 信号就会调用系统默认的 处理函数 会退出程序
头文件: #include
usecs :第一次什么时候发送时间
interval:微秒后在发送
signal(SIGALRM,fun); //给 SIGALRM信号绑定 fun函数
ualarm(50000000,200000000); // 5 秒后 发送 SIGALRM信号 ,并且 在2秒后 再次发送
setitimer() 设置精确定时器
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
头文件 #include
which:定时器类型
ITIMER_REAL:以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL:以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号
ITIMER_PROF:以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号
- new_value:struct itimerval 结构体类型
struct itimerval {
struct timeval it_interval; //隔几秒 触发时间
struct timeval it_value; //第一次触发时间
};
struct timeval {
time_t tv_sec; // 秒
suseconds_t tv_usec; // 微秒
};
getitimer() 获取精确定时器
int getitimerc(int which, struct itimerval *curr_value);
- 头文件 #include
- which:要获取的信号类型
- curr_value:返回 设置的curr_value
安装和捕获信号
- 忽略信号
- 自定义捕捉函数
- 系统默认信号函数
signal() 绑定信号函数 不推荐
- 忽略信号 和 屏蔽信号 是不一样的 屏蔽信号可以先存放 后处理
sigaction() 绑定信号函数 推荐
int sigaction(int signum, const struct sigaction act,
struct sigaction oldact);
可完成系统的所有信号操作
填充信号集合 sigfillset()
添加信号 sigdelset()
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 sa_mask; //信号屏蔽集合的处理函数
头文件:#include <signal.h>
int sigemptyset(sigset_t *set); //清空 信号集合
int sigfillset(sigset_t *set); //填满 信号集合
int sigaddset(sigset_t *set, int signum); //向信号集合添加信号
int sigdelset(sigset_t *set, int signum); //向信号集合删除信号
int sigismember(const sigset_t *set, int signum);//测试信号是否在信号集合中
struct siginfo_t {
int si_signo; /* Signal number */
int si_errno; /* An errno value */
int si_code; /* Signal code */
int si_trapno; /* Trap number that caused
hardware-generated signal
(unused on most architectures) */
pid_t si_pid; /* 给我发送信号的 ID */
uid_t si_uid; /* 发送信号的 用户 ID */
int si_status; /* Exit value or signal */
clock_t si_utime; /* User time consumed */
clock_t si_stime; /* System time consumed */
sigval_t si_value; /* 信号附带的值 */
int si_int; /* POSIX.1b signal */
void *si_ptr; /* POSIX.1b signal */
int si_overrun; /* Timer overrun count; POSIX.1b timers */
int si_timerid; /* Timer ID; POSIX.1b timers */
void *si_addr; /* Memory location which caused fault */
long si_band; /* Band event (was int in
glibc 2.3.2 and earlier) */
int si_fd; /* File descriptor */
short si_addr_lsb; /* Least significant bit of address
(since Linux 2.6.32) */
}
struct sigval_t si_value{
}
struct sigset_t ; //信号屏蔽集合的处理函数
- 头文件 : #include
int sigemptyset(sigset_t *set); //清空 信号集合
int sigfillset(sigset_t *set); //填满 信号集合
int sigaddset(sigset_t *set, int signum); //向信号集合添加信号
int sigdelset(sigset_t *set, int signum); //向信号集合删除信号
int sigismember(const sigset_t *set, int signum);//测试信号是否在信号集合中
sigprocmask() 设置信号屏蔽集合
int sigprocmask(int how, const sigset_t _set, sigset_t _oldset);
头文件: #include
用于指定信号修改的方式 :
SIG_BLOCK 把 set 加入到信号屏蔽集合中
SIG_UNBLOCK 把 set 从信号屏蔽集合中删除
SIG_SETMASK 设置为 set 屏蔽集合
set:struct sigset_t 要处理的信号集合
oldset: 是指向信号集的指针,在此存放原来的信号集
返回值 :成功返回0。失败返回-1,errno被设为EINVA
sigpending() 未决信号
- 未 屏蔽,也未处理的信号 = 未决信号
int sigpending(sigset_t *set);
该函数的作用是将被阻塞的信号中停留在待处理状态的一组信号写到参数set指向的信号集中
查看信号队列中是否有 未决信号
- 头文件:#include
- set :struct sigset_t 信号集合 用与存放 未决信号
sigismember() 判断信号是否在信号集合中
用来测试参数signum 代表的信号是否已加入至参数set 信号集里. 如果信号集里已有该信号则返回1, 否则返回0
int sigismember(const sigset_t *set, int signum);
- set :信号集合
- signum:判断是否存在的信号
sigsuspend() 替换信号集
屏蔽信号 : 屏蔽是会收到信号 会处理 但不会返回
接受一个信号集指针,将信号屏蔽字设置为信号集中的值,在收到不是信号集中的信号是才会执行 阻塞sigmask 中的信号
int sigsuspend(const sigset_t *sigmask);
- 头文件: #include
- sigmask:要替换的 sigset_t 集合
sem_init() 初始化信号
int sem_init(sem_t *sem, int pshared, unsigned int value);
- 头文件: #include
- 库 :-pthread
- sem: 指向信号量对象
- pshared : 指明信号量的类型
- value : 指定信号量值的大小
- 返回值:成功为 0 ,错误 -1
//sem_t,它本质上是一个长整型的数
sem_t siglen = 0;
sem_init(&siglen,0,0);
吧,siglen 设置为 0
sem_post() 给信号量的值加一
int sem_post(sem_t *sem);
- 头文件: #include
- 库 :-pthread
- sem:指向信号量对象
- 返回值:成功 0 ,没有更改 -1
sem_wait() 给信号量的值减一
int sem_wait(sem_t *sem);
如果 sem_wait -1的资源为负 就会阻塞 知道sem_post 才返回
- 头文件: #include
- 库 :-pthread
- sem:指向信号量对象
- 返回值:成功 0 ,没有更改 -1
socketpait 创建管道
- 返回值 fd 管道的 头 和 尾的 fd