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);
struct itimerval {
struct timerval it_value; // 闹钟触发时间
struct timerval it_interval; // 闹钟触发周期
}
struct timeval {
long tv_sec; // 秒
long tv_usec; // 微秒
}
/*
功能:
设置定时器。可替代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
*/
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;
// 第一次触发时间: 3s
tmo.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 + c
signal(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;
// 第一次触发时间: 3s
tmo.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;
}
运行结果: