软件中断:
信号名称(宏不会变),编号在不同的版本可能会变:
core保存进程异常退出的信息:
core.c:
#include <stdio.h>
#include <string.h>
int main() {
char * buf; // 指针 没有指向合法的内存 会产生段错误
strcpy(buf, "hello");
return 0;
}
kill.c:
/*
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
- 功能:给任何的进程或者进程组pid, 发送任何的信号 sig
- 参数:
- pid :
> 0 : 将信号发送给指定的进程
= 0 : 将信号发送给当前的进程组
= -1 : 将信号发送给每一个有权限接收这个信号的进程
< -1 : 这个pid=某个进程组的ID取反 (-12345)
- sig : 需要发送的信号的编号或者是宏值,0表示不发送任何信号 编号可能会变 但宏值不会变
kill(getppid(), 9);
kill(getpid(), 9);
int raise(int sig);
- 功能:给当前进程发送信号
- 参数:
- sig : 要发送的信号
- 返回值:
- 成功 0
- 失败 非0
kill(getpid(), sig);
void abort(void);
- 功能: 发送SIGABRT信号给当前的进程,杀死当前进程
kill(getpid(), SIGABRT);
*/
//演示kill
#include <stdio.h>
#include <sys/types.h>
#include <signal.h>
#include <unistd.h>
int main() {
pid_t pid = fork();
if(pid == 0) { //多进程是去抢夺CPU的执行权 父进程先执行还是子进程先执行 要抢占
// 子进程
int i = 0;
for(i = 0; i < 5; i++) {
printf("child process\n");
sleep(1);
}
} else if(pid > 0) {
// 父进程
printf("parent process\n");
sleep(2);
printf("kill child process now\n");
kill(pid, SIGINT);
}
return 0;
}
alarm.c: 只能定时一次
alarm作为定时器:时间过后,终止进程,返回剩余时间,每个进程只有一个定时器,想要停止定时器(传递个0)
// 1秒钟电脑能数多少个数?
#include <stdio.h>
#include <unistd.h>
/*
实际的时间 = 内核时间 + 用户时间 + 消耗的时间
进行文件IO操作的时候比较浪费时间
定时器,与进程的状态无关(自然定时法)。无论进程处于什么状态,alarm都会计时。
*/
int main() {
alarm(1);
int i = 0;
while(1) {
printf("%i\n", i++);
}
return 0;
}
setitimer.c:(读音:set i timer) 与alarm的区别是能周期性定时
/*
#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
- 功能:设置定时器(闹钟)。可以替代alarm函数。精度微妙us,可以实现周期性定时
- 参数:
- which : 定时器以什么时间计时
ITIMER_REAL: 真实时间,时间到达,发送 SIGALRM 常用
ITIMER_VIRTUAL: 用户时间,时间到达,发送 SIGVTALRM
ITIMER_PROF: 以该进程在用户态和内核态下所消耗的时间来计算,时间到达,发送 SIGPROF
- new_value: 设置定时器的属性 是个结构体
struct itimerval { // 定时器的结构体
struct timeval it_interval; // 每个阶段的时间,间隔(interval)时间
struct timeval it_value; // 延迟多长时间执行定时器
};
struct timeval { // 时间的结构体
time_t tv_sec; // 秒数
suseconds_t tv_usec; // 微秒
};
过10秒后,每个2秒定时一次
- old_value :记录上一次的定时的时间参数,一般不使用,指定NULL
- 返回值:
成功 0
失败 -1 并设置错误号
*/
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
// 过3秒以后,每隔2秒钟定时一次
int main() {
struct itimerval new_value;
// 设置间隔的时间
new_value.it_interval.tv_sec = 2;
new_value.it_interval.tv_usec = 0;
// 设置延迟的时间,3秒之后开始第一次定时
new_value.it_value.tv_sec = 3;
new_value.it_value.tv_usec = 0;
int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的 ITIMER_REAL 默认去终止进程,所以没法周期性定时,需要信号捕捉,才能周期性定时
printf("定时器开始了...\n"); //他立马打印,并没有延迟三秒,说明是非阻塞的
if(ret == -1) {
perror("setitimer");
exit(0);
}
getchar();
return 0;
}
signal.c:
/*
#include <signal.h>
typedef void (*sighandler_t)(int);
sighandler_t signal(int signum, sighandler_t handler);
- 功能:设置某个信号的捕捉行为
- 参数:
- signum: 要捕捉的信号
- handler: 捕捉到信号要如何处理
- SIG_IGN : 忽略信号
- SIG_DFL : 使用信号默认的行为 (相当于没有捕捉)
- 回调函数 : 这个函数是内核调用,程序员只负责写,捕捉到信号后如何去处理信号。
回调函数:
- 需要程序员实现,提前准备好的,函数的类型根据实际需求,看函数指针的定义
- 不是程序员调用,而是当信号产生,由内核调用
- 函数指针是实现回调的手段,函数实现之后,将函数名放到函数指针的位置就可以了。
- 返回值:
成功,返回上一次注册的信号处理函数的地址。第一次调用返回NULL
失败,返回SIG_ERR,设置错误号
SIGKILL(强制杀死某个进程,要是能捕捉,可以搞病毒了) SIGSTOP不能被捕捉,不能被忽略。
*/
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
void myalarm(int num) {
printf("捕捉到了信号的编号是:%d\n", num);
printf("xxxxxxx\n");
}
// 过3秒以后,每隔2秒钟定时一次
int main() {
// 注册信号捕捉 要写在最前面
// signal(SIGALRM, SIG_IGN);
// signal(SIGALRM, SIG_DFL);
// void (*sighandler_t)(int); 函数指针,int类型的参数表示捕捉到的信号的值。
signal(SIGALRM, myalarm);
struct itimerval new_value;
// 设置间隔的时间
new_value.it_interval.tv_sec = 2;
new_value.it_interval.tv_usec = 0;
// 设置延迟的时间,3秒之后开始第一次定时
new_value.it_value.tv_sec = 3;
new_value.it_value.tv_usec = 0;
int ret = setitimer(ITIMER_REAL, &new_value, NULL); // 非阻塞的
printf("定时器开始了...\n");
if(ret == -1) {
perror("setitimer");
exit(0);
}
getchar();
return 0;
}
回调函数:
回调函数(Callback Function)是一种特殊类型的函数,它作为参数传递给另一个函数,并在特定的事件发生或条件满足时由另一个函数来调用。当满足一定条件时,被调用的函数将执行特定的操作或逻辑。
回调函数的使用可以实现灵活的控制流和事件处理机制。常见的应用场景包括事件驱动编程、异步编程、GUI 编程以及处理回调接口等。
回调函数的特点如下:
函数作为参数传递:回调函数通常作为另一个函数的参数传递。这样,调用者可以决定在何时调用回调函数。
非阻塞执行:回调函数通常在某个事件触发或条件满足时被调用,因此不会阻塞程序的执行。
逻辑分离:将特定的操作或逻辑封装在回调函数中,可以使代码更加模块化和可维护。
具体来说,回调函数的用法如下:
定义回调函数:编写一个函数,其中包含特定的操作或逻辑,用于在特定条件下被调用。
注册回调函数:将回调函数作为参数传递给另一个函数,并在合适的时机注册该回调函数。
触发回调:当满足特定的条件时,调用者会触发回调函数,从而执行相应的操作。
回调函数通常用于异步编程、事件处理和处理非线性控制流等情况下。通过使用回调函数,可以将程序的控制权交给调用者,使得程序能够更加灵活和可扩展。