一、unix。linux体系结构
结构
内核 -> 系统调用 -> 公用库函数/shell -> 外部程序
类unix体系结构分为两个状态
- (1)用户态
- (2)内核态
操作系统/内核
:用来控制计算机硬件资源,提供应用程序的运行环境
我们写的程序一般
是在用户态
,但是一些特殊
的代码
的时候会切换到内核态
系统调通
就是一些系统函数
shell:
bash
(borne again shell重新装配的shell),它就是一种shell
,linux默认
采用的是bash
着这种shell
通俗一点,bash
是一个可执行程序
,主要作用就是:命令解释
whereis bash
/usr/bin/bash
bash可以嵌套:
exit,exit,bash嵌套bash
shell的目的:
分割系统调用和应用程序
二、用户态和内核态之间的切换
内核态和用户态的不同:
- 运行于用户态的进程可执行的操作和访问的资源会受到极大的限制
- 内核态进程可进行任何操作,并且资源上没有限制
一个进程执行的时候,大部分时间都在用户态,但是有时候需要内核提供的服务
会切换到内核态,服务完成之后,再次切回来
为什么要这样划分,用户态,内核态
- 1、避免危险操作
- 2、系统调用的这些接口也是操作系统统一管理的
资源是有限的,解决访问冲突,
什么时候从用户态切换到内核态?
- 1、系统调通,比如malloc(sizeof(int))
- 2、异常事件,信号
- 3、外围设备中断
三、signal函数范例
可重入函数
:在信号处理函数中,调用的时候,保证是安全的,异步调用安全
大家周知的函数都是不可重入的
如:malloc,printf
有些是可重用,异步安全函数,有些不是,自行百度
因为系统函数中由int error = num
但是如果你在信号处理中出错了,正常函数也出错了,那么这个error就不能正确显示错误了
信号处理函数原则:
- 1、在信号处理中,尽量简单,尽量不要调用系统函数
- 2、如果必须调用系统函数,那么一定调用可重入的,异步信号安全的系统函数
- 3、如果一定要在信号处理中一定要调用会修改errno的值的函数,一定要备份,最终回复一下
signal不建议使用,知识在demo中使用一下
信号处理错误使用不可重用函数案例:
#include<stdio.h>
#include<unistd.h>
#include<signal.h>
#include<stdlib.h>
void sigHandler(int signo)
{
void* p;
//malloc是不可重用函数
p = (void*)malloc(1);
free(p);
if (signo == SIGUSR1)
{
printf("捕捉到了SIGUSR1信号\n");
}
else if (signo == SIGUSR2)
{
printf("捕捉到了SIGUSR2信号\n");
}
else
{
printf("收到了未捕捉的信号d%\n", signo);
}
}
int main()
{
printf("process start");
if (signal(SIGUSR1, sigHandler) == SIG_ERR)
{
printf("无法捕捉SIGUSR1信号");
}
if (signal(SIGUSR2, sigHandler) == SIG_ERR)
{
printf("无法捕捉SIGUSR2信号");
}
for (; ;)
{
void* p;
p = (int*)malloc(sizeof(1));
free(p);
}
}
bash1中进行编译,启动
bash2中查看运行状态,并给进程一个LinuxTestCSave信号
R+表示前台运行
查看运行状态
S+表示已经休眠了,程序已经出错了