信号
信号
一、主要函数:signal();alarm();pause();setitimer();sigprocmask();sigaction();
二、
kill -l 列出当前支持的信号
不存在编号为0 的信号
普通信号不排队,实时信号排队( 但一般我们用不着)
异种信号允许嵌套,即一个未完也可嵌入另一个;
同种信号不允许嵌套,同种信号不排队,所以为了防止信号丢失,信号处理一定要快。
1 、signal
对信号的处理有三种方式:
1) 捕捉信号,signal(SIGINT,sig_handler); void sig_handler(int s);
2) 忽略信号,signal(SIGINT,SIG_IGN);
3) 执行系统默认动作,signal(SIGINT,SIG_DFL);
2 、/*setitimer() 可以定时在微秒级,产生SIGALRM 信号*/
3 、
1)pause() 每两秒钟就被唤醒一次
2) 有信号传递则会被唤醒
3) 它会使调用它的进程阻塞
4 、三种方法收僵尸:
1 )用sigaction 的SA_NOCLDWAIT 让子进程退出时不产生僵尸
2 )当很多僵尸时,用for (i = 0; i < CHILDNUM; i++) {
wait(NULL);
} 这种方法来收僵尸是不好的
3 )while (waitpid(-1, NULL, WNOHANG));
5 、
1) 如果不对SIGALRM 信号作处理的话,该信号会使程序退出。
2)alarm() 的返回值是上一次没有完成的秒数。
6 、
1) 与信号集sigset_t 类型有关, 五个信号集处理函数:sigXXXXset,sigismember
2)sigpending() 返回当前已挂上但没传进去的一个信号集
3)sigprocmask 主要有三个参数:SIG_BLOCK,SIG_UNBLOCK,SIG_SETMASK;
7 、
sigaction 常用的几个参数:SA_INTERRUPT, SA_RESTART,SA_NOCLDWAIT
SA_INTERRUPT: 被这个信号打断的系统调用不会自动重启。
SA_RESTART : 被这个信号打断的系统调用会自动重启。
SA_NOCLDWAIT :若sigaction 的第一个参数为SIGCHLD, 则当调用进程的子进程终止时,不创建僵尸。
三、例程
1 、
/*signal.c*/
#include <stdio.h>
#include <signal.h>
void sig_handler(int s)
{
if (s == SIGINT) {
printf("Hello world!/n");
} else if (s == SIGQUIT)
printf("hello!/n");
}
int main(void)
{
signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler);
while (1) {
// printf("hello world!/n");
sleep(1);
}
}
/*signal 信号处理函数. 如果想忽略一个信号, 如:signal(SIGINT,SIG_IGN)*/
2 、
/*setitimer.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <sys/time.h>
#define BUFSIZE 2
void alarm_handler(int s)
{
}
int main(void)
{
int fd, ret;
char buf[BUFSIZE];
struct itimerval cur;
cur.it_value.tv_sec = 0;//给定时器装初值,it_value刚开始不能为0?
cur.it_value.tv_usec = 1;
cur.it_interval.tv_sec = 0;
cur.it_interval.tv_usec = 50000;
signal(SIGALRM, alarm_handler);
setitimer(ITIMER_REAL, &cur, NULL);//相当于单片机的定时/计数器
fd = open("/etc/services", O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}
while (1) {
ret = read(fd, buf, BUFSIZE);
if (ret == 0)
break;
write(1, buf, ret);
pause();
}
close(fd);
exit(0);
}
/*setitimer()可以定时在微秒级,产生SIGALRM信号*/
3 、
/*sigaction.c*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
void int_handler(int s)
{
}
int main(void)
{
int ret;
char buf[32];
struct sigaction act;
act.sa_handler = int_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_INTERRUPT;
// act.sa_flags = SA_RESTART;
sigaction(SIGINT, &act, NULL);
sigaction(SIGQUIT, &act, NULL);
// signal(SIGINT, int_handler);
while (1) {
ret = read(0, buf, 32);
if (ret == -1) {
if (errno == EINTR) {
perror("read");
continue;
}
perror("read");
break;
}
}
return 0;
}
/*sigaction 常用的几个参数:SA_INTERRUPT, SA_RESTART,SA_NOCLDWAIT
SA_INTERRUPT: 被这个信号打断的系统调用不会自动重启。
SA_RESTART : 被这个信号打断的系统调用会自动重启。
SA_NOCLDWAIT :若sigaction 的第一个参数为SIGCHLD, 则当调用进程的子进程终止时,不创建僵尸。
*/
4 、
/*sigprocmask.c*//*有些时候,我们暂时不希望受到某些信号的干挠,暂且将其屏蔽*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
int main(void)
{
sigset_t cur, old, pending;
sigemptyset(&cur);
sigaddset(&cur, SIGINT);
sigaddset(&cur, SIGQUIT);
sigaddset(&cur, SIGALRM);
alarm(1);
while (1) {
sigprocmask(SIG_BLOCK, &cur, &old);
printf("A/n");
sleep(5);
printf("B/n");
sigpending(&pending);
if (sigismember(&pending, SIGINT))
printf("sigint is here!/n");
if (sigismember(&pending, SIGQUIT))
printf("sigquit is here!/n");
if (sigismember(&pending, SIGALRM))
printf("sigalrm is here!/n");
sigprocmask(SIG_SETMASK, &old, NULL);//解除mask后,pending上已挂有的就会起作用
sleep(1);
}
}
/*1、与信号集sigset_t类型有关,五个信号集处理函数:sigXXXXset,sigismember
2、sigpending()返回当前已挂上但没传进去的一个信号集
3、sigprocmask主要有三个参数:SIG_BLOCK,SIG_UNBLOCK,SIG_SETMASK;
*/
5 、
/*alarm.c*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <signal.h>
void sig_handler(int s)
{
printf("alram!/n");
}
int main(void)
{
int ret;
alarm(10);
sleep(5);
ret = alarm(3);
printf("ret=%d/n", ret);
signal(SIGALRM, sig_handler);
while (1)
sleep(1);
#if 0
char buf[32];
while (1) {
printf("Input content!(It will exit! after" " 10 second): ");
fflush(stdout);
read(0, buf, 32);
}
#endif
}
/*1 、如果不对SIGALRM 信号作处理的话,该信号会使程序退出。
2 、alarm() 的返回值是上一次没有完成的秒数。*/
6 、
/*divide.c*/
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int a = 100;
int b = 0;
int c = a / b;
printf("sucess!/n");
exit(0);
}
/* 除以0 会产生异常,程序直接退出*/
7 、
/*zombie.c*//* 三种收僵尸的方法*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/types.h>
#define CHILDNUM 10000
void destroy_zombie(int s)
{
while (waitpid(-1, NULL, WNOHANG));
}
int main(void)
{
int i;
pid_t pid;
struct sigaction act;
act.sa_handler = destroy_zombie;
sigemptyset(&act.sa_mask);
//act.sa_flags = SA_NOCLDWAIT;
act.sa_flags = SA_RESTART;
sigaction(SIGCHLD, &act, NULL);
for (i = 0; i < CHILDNUM; i++) {
pid = fork();
if (pid == 0) {
exit(0);
}
}
#if 0
for (i = 0; i < CHILDNUM; i++) {
wait(NULL);
}
#endif
while (1) {
// printf("Hello!/n");
sleep(1);
}
}
/*1 、用sigaction 的SA_NOCLDWAIT 让子进程退出时不产生僵尸*/
/*2 、当很多僵尸时,用for (i = 0; i < CHILDNUM; i++) {
wait(NULL);
} 这种方法来收僵尸是不好的*/
/*3 、while (waitpid(-1, NULL, WNOHANG));*/
8 、
/*pause.c*/
#include <stdio.h>
#include <signal.h>
void sig_handler(int s)
{
alarm(2);
}
int main(void)
{
signal(SIGALRM, sig_handler);
alarm(2);
while (1) {
printf("I am sleeping..../n");
pause();
}
}
/*1 、pause() 每两秒钟就被唤醒一次
2 、有信号传递则会被唤醒
3 、它会使调用它的进程阻塞
*/
9 、
/*sigifque.c*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
static int cnt = 0;
void sig_handler(int s)
{
printf("hello:%d/n", cnt++);
sleep(5);
return;
}
int main(void)
{
signal(SIGINT, sig_handler);
while (1)
sleep(1);
return 0;
}
/* 在sleep(5) 内,若来多个SIGINT ,则会丢失,因为普通信号是不排队的*/
10 、
/*order.c*//* 信号是否排队*/
#include <stdio.h>
#include <signal.h>
static int cnt = 0;
void sig_handler(int s)
{
// if (s == SIGINT) {
printf("Hello world!:%d/n", cnt++);
sleep(5);
// } else if (s == SIGQUIT)
// printf("hello!:%d/n", cnt++);
}
int main(void)
{
signal(SIGINT, sig_handler);
signal(SIGQUIT, sig_handler);
while (1) {
sleep(1);
}
}
/*1 、sig_handler 的参数s 所传入的值对应所发生的信号
2 、这个程序说明:
异种信号允许嵌套,那一个未完也可嵌入另一个;
同种信号不允许嵌套,同种信号不排队,所以为了防止信号丢失,信号处理一定要快。
*/
11 、
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
void alram_handler(int s)
{
printf("Do homework!!!!/n");
}
int main(void)
{
char buf[32];
memset(buf, 0, 32);
struct sigaction act;
act.sa_handler = alram_handler;
sigemptyset(&act.sa_mask);
act.sa_flags = SA_RESTART;
alarm(5);
sigaction(SIGALRM, &act, NULL);
int ret = read(0, buf, 31);
printf("read:%s/n", buf);
exit(0);
}
/* SA_RESTART 使read 的不阻塞*/
12 、
/* 模拟流量控制*/
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#define BUFSIZE 15
static int count = 0;
void alarm_handler(int s)
{
count += BUFSIZE;// 每三秒只能读15 个?
alarm(3);
// printf("need read amount:%d/n", count);
}
int main(void)
{
int ret, fd;
char buf[BUFSIZE];
fd = open("/etc/services", O_RDONLY);
if (fd == -1) {
perror("open");
exit(1);
}
alarm(3);
signal(SIGALRM, alarm_handler);
while (1) {
if (count == 0)
pause();// 刚开始等待闹钟把它唤醒, 醒了之后count=15 了
ret = read(0, buf, BUFSIZE);
if (ret == 0)
break;
write(1, buf, ret);
count -= ret;
}
close(fd);
exit(0);
}
- 上一篇: CAAnimation 如何解决保持动画最后的状态不变
- 下一篇: sigaction 使用