1. kill函数
#include<sys/types.h>
#include<signal.h>int kill(pid_t pid, int sig);
/*
功能:给进程pid发送信号sig
参数:pid:取值有4种情况:> 0:将sig信号发送给进程号为pid的进程;= 0:将sig信号发送给当前进程组中的所有进程;= -1:将sig信号发送给系统内的所有进程;< -1:将sig信号发送给进程组号为pid绝对值的进程组中的所有进程。sig:信号。推荐使用信号宏。
返回值:成功:0;失败:-1
*/
a)root权限用户可给任意用户发信号,普通用户不可给root权限用户发信号;
b)普通用户不允许:kill -9 root用户进程的pid; 普通用户也不允许向其他普通用户发送信号终止其进程,只能向自己创建的进程发送信号;普通用户只能给自己的进程发送信号。
kill函数示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>int main(int argc, const char* argv[]) {pid_t pid = -1;int ret = -1;// 创建一个子进程pid = fork();if (-1 == pid) {perror("fork");return 1;}// 父进程杀死子进程if (pid > 0) { // 父进程sleep(3);ret = kill(pid, SIGTERM);if (-1 == ret) {perror("kill");return 1;}printf("子进程被杀死!\n");} else { // 子进程while (1) {printf("子进程运行中...\n");sleep(1);}exit(0);}return 0;
}
运行结果:
2. raise函数
#include<signal.h>int raise(int sig);
/*
功能:当前进程给自己发送信号sig,相当于kill(getpid(), sig);
参数:sig:信号宏;
返回值:成功:0失败:非0
*/
raise函数示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<sys/types.h>
#include<signal.h>
#include<unistd.h>int main(int argc, const char* argv[]) {int i = 4;while (1) {printf("进程%d自杀倒计时: %d\n", getpid(), i);sleep(1);if (0== --i) {printf("进程%d杀死自己.\n", getpid());raise(SIGTERM);}}return 0;
}
运行结果:
3. abort函数
#include<stdlib.h>void abort(void);
/*
功能:给自己发送异常终止信号,即6号信号SIGABTR,并产生core文件。等价于kill(getpid(), SIGABRT);
*/
abort函数示例:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<string.h>int main(int argc, const char* argv[]) {int i = 3;while (1) {printf("终止倒计时:%d\n", i--);sleep(1);if (0 == i) {printf("进程终止!\n");abort();}}return 0;
}
运行结果:
4. alarm函数
定时器
#include<unistd.h>unsigned int alarm(unsigned int seconds);
/*
功能:设置定时器:指定seconds后,内核给当前进程发送14号信号SIGALRM信号,进程收到该信号,默认终止进程。每个进程有且只有唯一的定时器。
参数:seconds:定时时间,单位s;为0时则表示取消定时器,并返回旧闹钟剩余秒数。
返回值:0或剩余秒数。
*/
注意:alarm函数与调用进程状态无关。进程处于任何状态(退出除外),alarm都会计时。
alarm函数示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>int main(int argc, const char* argv[]) {unsigned int ret = 0;ret = alarm(5);sleep(3); // 进程的sleep状态不会影响闹钟的计时ret = alarm(4); // 覆盖之前的闹钟,重新计时/* 结果为2. 第一次计时5秒,sleep了3秒,执行到第二个闹钟时,第一次闹钟剩余2s*/printf("上次闹钟剩下的时间:%u\n", ret);getchar();return 0;
}
运行结果:
前后总共计时7s
5. setitimer函数
多功能定时器
#include<sys/time.h>int setitimer(int which, const struct itimerval* new_value, struct itimerval* old_value);
/*
功能:设置定时器。可替代alarm,精度μs。可实现周期定时。
参数:which:定时方式:a) 自然定时:ITIMER_REAL(14号信号,SIGALRM),计算自然时间,默认终止进程;b) 虚拟空间计时(用户空间):ITIMER_VIRTUAL(26号信号,SIGVTALRM),只计算占CPU时间;c) 运行时计时(用户+内核):ITIMER_PROF(27号信号,SIGPROF),计算占用CPU+系统调用时间;new_value:超时时间;itimerval.it_value:第一次执行function延迟的秒数;itimerval.it_interval:以后执行function的时间间隔old_value:存放旧的timeout值,一般为NULL
返回值:成功:0;失败:-1
*/struct itimerval {struct timerval it_value; // 闹钟触发时间struct timerval it_interval; // 闹钟触发周期
}struct timeval {long tv_sec; // 秒long tv_usec; // 微秒
}
setitimer示例:
#include<stdio.h>
#include<sys/time.h>
#include<stdlib.h>
#include<string.h>int main(int argc, const char* argv[]) {int ret = -1;struct itimerval tmo;// 第一次触发时间: 3stmo.it_value.tv_sec = 3;tmo.it_value.tv_usec = 0;// 触发周期: 2s一次。 此处无效果,需结合后面的信号捕捉使用。tmo.it_interval.tv_sec = 2;tmo.it_interval.tv_usec = 0;// 设置定时器, 默认动作:终止进程ret = setitimer(ITIMER_REAL, &tmo, NULL);if (-1 == ret) {perror("setitimer");return 1;}printf("按下任意键继续\n");getchar();return 0;
}
运行结果:
6. signal函数
注册信号处理函数。
注:由于历史原因,signal函数在不同版本的类Unix系统中含义不同,应避免使用signal函数。
#include<signal.h>typedef void(*sighandler_t)(int);
/*
函数指针。
名字:sighandler_t,返回值:void,形参:一个int类型;
*/sighandler_t signal(int signum, sighandler_t handler);
/*
功能:注册信号处理函数:收到signum信号,则执行handler函数。不可用于SIGKILL、SIGSTOP信号。
参数:signum:信号编号,建议写信号的宏;handler:3中取值情况:SIG_IGN:忽略该信号;SIG_DFL:执行默认处理方式;回调函数名:自定义处理方式;回调函数定义如下:void func(int signo) {// signo为触发的信号,为signal函数的第一个参数}
返回值:成功:第一次返回NULL,下一次返回此信号上次注册的信号处理函数的地址;若需要使用此返回值,则必须在前面声明此函数的指针类型。失败:SIG_ERR
*/
signal示例1:
捕捉Ctrl+c、Ctrl+\信号,并自定义各自的处理方式。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>
#include<unistd.h>void func0(int signum) {printf("捕捉到信号:%d\n", signum);
}void func1(int signum) {printf("捕捉到信号:%d\n", signum);
}int main(int argc, const char* argv[]) {/*注册信号处理函数。*/// SIGINT: Ctrl + csignal(SIGINT, func0); // 处理异步信号/*SIGQUIT: Ctrl + \*/signal(SIGQUIT, func1);while (1) {getchar();}return 0;
}
运行结果:
signal示例2:
捕捉setitimer信号,修改它默认终止进程的行为。
#include<stdio.h>
#include<sys/time.h>
#include<stdlib.h>
#include<string.h>
#include<signal.h>void func(int signum) {printf("捕捉到SIGALRM信号.\n");
}int main(int argc, const char* argv[]) {int ret = -1;struct itimerval tmo;// 第一次触发时间: 3stmo.it_value.tv_sec = 3;tmo.it_value.tv_usec = 0;// 触发周期: 2s一次。 此处无效果,需结合后面的信号捕捉使用。tmo.it_interval.tv_sec = 2;tmo.it_interval.tv_usec = 0;// 捕捉信号SIGALRM,修改它的默认处行为。signal(SIGALRM, func);// 设置定时器, 默认动作:终止进程ret = setitimer(ITIMER_REAL, &tmo, NULL);if (-1 == ret) {perror("setitimer");return 1;}printf("按下任意键继续\n");getchar();return 0;
}
运行结果:
7. sigaction函数
改变指定信号的处理方式,功能类似于signal。
#include<signal.h>int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
/*
功能:修改或检查signum信号的处理方式。
参数:signum:要操作的信号;act:信号的新处理方式;传入参数;oldact:信号原先的处理方式;传出参数;若act非空,则将信号原处理方式变为act;若oldact非空,则将先前的处理方式存入oldact。
返回值:成功:0失败:-1
*/struct sigaction {void(*sa_handler)(int); // 旧的信号处理函数指针void(*sa_sigaction)(int, siginfo_t*, void*); // 新的信号处理函数指针sigset_t sa_mask; // 阻塞信号集int sa_flags; // 信号处理方式void(*sa_restorer)(void); // 已弃用
}
/*
(1) sa_handler、sa_sigaction:信号处理函数指针,与signal函数中的函数指针用法一样,根据情况给两者之一赋值。a) SIG_IGN:忽略该信号b) SIG_DFL:执行默认处理方式c) 回调函数名:自定义处理方式
(2) sa_mask:阻塞信号集。信号处理函数执行过程中,临时屏蔽指定信号。
(3) sa_flags:指定信号处理行为,通常设置为0(使用旧的信号处理函数). 也可是以下值的"按位或"组合SA_NOCLDSTOP:使父进程在其子进程暂停或继续运行时不会收到SIGCHLD;SA_NOCLDWAIT:使父进程在其子进程退出时不会收到SIGCHLD信号,此时子进程也不会成为僵尸进程;SA_NODEFER:使对信号的屏蔽无效,即在信号处理函数执行期间仍能收到该信号;SA_RESETHAND:信号处理之后重新设置为默认的处理方式;SA_SIGINFO:使用sa_sigaction成员而不是sa_handler作为信号处理函数;SA_RESTART:使被信号打断的系统调用自动重新发起(已废弃);
*/void(*sa_sigaction)(int, siginfo_t*, void*);
/*
功能:新的信号处理函数指针,
参数:signum:信号编号;info:记录信号发送进程信息的结构体;context:赋给指向ucontext_t类型的一个对象指针,以引用在传递信号是被中断的接收进程或线程的上下文。
*/
sigaction示例1:
旧的信号处理函数:
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>// 信号处理函数
void func(int signum) {printf("捕捉到信号%d.\n", signum);
}int main(int argc, const char* argv[]) {int ret = -1;struct sigaction act;act.sa_handler = func; // 自定义旧的信号处理函数act.sa_flags = 0; // 使用旧的信号处理函数ret = sigaction(SIGINT, &act, NULL);if (-1 == ret) {perror("sigaction");return 1;}printf("按下任意键继续...\n");getchar();return 0;
}
运行结果:
sigaction示例2:
新的信号处理函数:
#include<stdio.h>
#include<signal.h>
#include<stdlib.h>
#include<string.h>// 信号处理函数
void func(int signum, siginfo_t* info, void* context) {printf("捕捉到信号%d.\n", signum);
}int main(int argc, const char* argv[]) {int ret = -1;struct sigaction act;act.sa_sigaction = func; // 自定义新的信号处理函数act.sa_flags = SA_SIGINFO; // 使用新的信号处理函数ret = sigaction(SIGINT, &act, NULL);if (-1 == ret) {perror("sigaction");return 1;}printf("按下任意键继续...\n");getchar();return 0;
}
运行结果:
8. sigqueue函数
#include<signal.h>int sigqueue(pid_t pid, int sig, const union sigval value);
/*
功能:给指定进程发送信号。
参数:pid:进程号;sig:信号;value:通过信号传递的参数。union sigval {union sigval {int sival_int;void* sival_ptr;}}
返回值:成功:0失败:-1
*/