惠州做网站广告,内蒙古建设银行网站,丰县建设局规划局网站,种子搜索网站开发目录
信号量
时序问题
原子性
什么是信号 信号如何产生
引入
信号的处理方法
常见信号
如何理解组合键变成信号呢#xff1f;
如何理解信号被进程保存以及信号发送的本质#xff1f;
为什么要有信号
信号怎么用#xff1f;
样例代码
core文件有什么用呢#…目录
信号量
时序问题
原子性
什么是信号 信号如何产生
引入
信号的处理方法
常见信号
如何理解组合键变成信号呢
如何理解信号被进程保存以及信号发送的本质
为什么要有信号
信号怎么用
样例代码
core文件有什么用呢
验证core的状态 一般生产环境为什么要关闭core
kill结束进程
软件条件产生的信号
硬件产生的信号
如何理解除0错误
如何理解野指针和越界问题 由于临界区和临界资源的存在在进入临界区访问呢临界资源的时候必须要先申请一个信号量。通知临界区提前预定访问临界资源。对临界资源访问的预定。只有我这个进程访问完成之后其他的资源才可以访问呢。
信号量
时序问题
信号量本质上是一个计数器。
假有一个变量n 6需要多次--多个进程执行
cpu执行指令的时候将内存中的数据加载到cpu内部的寄存器中读指令之后(n--)分析执行命令然后将cpu修改之后的数据写回内存。进程在执行的时候任何时候都可能被切换。寄存器只有一套被所有执行流共享但是寄存器数据是单独的属于执行流的上下文。
假设一个进程刚对n执行--到5然后结果没写入被切换了然后其他的进程对n--到0写回去结果此刻之前的进程继续执行将5写回去这回导致之前的进程工作白费。这就引出了时序问题。这种执行是不安全的。
原子性
为了保证避免时序问题就需要保证每个临界资源被访问只能一个进程执行完另一个进程继续执行。这种就叫做原子性。
什么是信号
首先信号和信号量是2个东西。linux信号本质上是一中通知机制用户或者操作系统通过发送一定的信号。通知进程某些事件已经发生你可以在进行后续处理。结合进程我们可以得出以下结论 a.进程必须有识别进程的能力 b.为什么能识别信号呢通过程序员的逻辑处理 c.信号到来是随机的进程可能在忙自己的事情信号的后续处理可能不是立即处理的。就像打游戏时候外卖送过来。 d.信号会被临时记录下对应的信号方便后续的处理。 e.在什么时候处理呢合适的时候 f.一般而言信号的产生和进程都是异步的。 信号如何产生
引入
当一个程序运行的时候我们在键盘上按ctrl c本质上就是通过键盘组合向目标发送2号信号。让程序结束。
信号的处理方法
a.默认 每个信号都有默认的信号处理方法。(进程自带的)
b.忽略也是信号的一种处理方式
c.自定义捕捉信号自己处理
常见信号
kill -l 此命令查看所有信号 1-31为普通信号没有0号3233号信号。34-64是实时信号。我们一般只关心1-31.
我们使用 man 7 signal 查看 里面有一个action 默认处理行为。
如何理解组合键变成信号呢
键盘的工作方式是通过中断方式进行的可以识别组合键。操作系统解释组合键查找进程列表找到相关的进程修改内部数据结构。
如何理解信号被进程保存以及信号发送的本质
为了识别信号进程必须保存信号相关的信号数据结构。怎么表示呢位图。pcb内部保存了信号位图字段。
信号位图是在task_struct里面保存的。发送信号的时候操作系统修改pcb内部位图字段。也就是说发信号本质上就是修改操作系统内部指定的位图结构完成发送信号的过程。
为什么要有信号
a.是什么信号
b.是否产生 信号怎么用
介绍一个函数
#include signal.htypedef void (*sighandler_t)(int);sighandler_t signal(int signum, sighandler_t handler);这个函数可以对信号进行自定义。参数1是对哪个信号进行捕捉信号的类型参数二是函数指针回调函数。通过回调的方式修改信号的处理方法。
样例代码
#includeiostream
#includesignal.h
#includesys/types.h
#includeunistd.h
using namespace std;//信号捕捉
void catchsig(int sigum)
{cout捕捉到了信号:sigumpid:getpid()endl;
}int main()
{//SIGINT是二号信号在用户输入ctrl信号时发出。用于通知前台结束进程signal(SIGINT,catchsig);//也可以直接写数字名字都可以,第一个参数是信号处理选项//信号的处理方法一般只有一个signal(SIGQUIT,catchsig);//二号和三号信号捕捉。//signal仅仅是修改进程对特定信号处理方法而不是直接调用处理方法while(1){//加循环是为了给信号产生留下时间cout我是一个进程在运行。。。pid:getpid()endl;sleep(1);}return 0;
}
在之前我们查看信号的时候action里面有2个选项term 和 core
那么core是什么呢core全程core dump核心转储标志表示是否发送核心转储。一般而言核心转储是被关闭的。 首先解释什么是Core Dump。当一个进程要异常终止时,可以选择把进程的用户空间内存数据全部保存到磁 盘上,文件名通常是core,这叫做Core Dump。进程异常终止通常是因为有Bug,比如非法内存访问导致段错误, 事后可以用调试器检查core文件以查清错误原因,这叫做Post-mortem Debug事后调试)。一个进程允许 产生多大的core文件取决于进程的Resource Limit(这个信息保存 在PCB中)。默认是不允许产生core文件的, 因为core文件中可能包含用户密码等敏感信息,不安全。在开发调试阶段可以用ulimit命令改变这个限制,允许 产生core文件。 首先用ulimit命令改变Shell进程的Resource Limit,允许core文件最大为1024K: ulimit -a 这个命令可以查看服务器状态里面会显示core的状态。
可以使用ulimit -c 1024命令打开core状态并指定core为1024字节。如果我们使用带有 core的信号的时候例如8号信号结束程序程序会结束时带有core.并且生成core文件以自己的pid为结尾。 core文件有什么用呢
当进程出现异常的时候由系统将当前进程内存中的核心数据dump到磁盘中。也就是core文件。
那么为什么要转储呢——调试。
在使用调试生成文件之后使用gdb进行调试 core-file加载定位文件。可以直接定位到出错位置。 验证core的状态 int status 0;waitpid(id,status,0);cout父进程getppid()子进程getpid() 退出码 status0x7f是否 core(status71)endl; 一般生产环境为什么要关闭core
生产环境内存空间有限因为有时候服务可能不可抗力导致一直重启一直生产core文件极有可能塞满内存空间出问题。
信号接口
kill结束进程 #include signal.h int kill(pid_t pid, int signo); 向指定进程发送指定信号。 int raise(int signo); 这两个函数都是成功返回0,错误返回-1 自己给自己发送自己定义的信号。 #include void abort(void); 就像exit函数一样,abort函数总是会成功的,所以没有返回值。 自己终止自己。想当于自己给自己发6号信号 系统调用本质上也就是操作系统修改对应的数据结构。
软件条件产生的信号
管道——独端不读而且一直写会发生什么系统会自动终止通过发送信号的方式SIGPIPE. include unistd.h unsigned int alarm(unsigned int seconds); 调用alarm函数可以设定一个闹钟,也就是告诉内核在seconds秒之后给当前进程发SIGALRM信号, 该信号的默认处理动 作是终止当前进程。 #includeiostream
#includesys/types.h
#includeunistd.h
#includesys/wait.h
using namespace std;
#includesignal.h
#includestringint main()
{alarm(1);int count 0;while(1){coutcout :countendl;}}这个代码是计算一秒钟count了多少次 虽然这个数很大但是相比于cpu的性能其实很拉跨这是为什么呢
cout大量IO很消耗时间还有网络传输发送导致非常慢。
闹钟有一个问题一旦使用过就会自动移除。那么闹钟如果想要周期性的使用怎么办呢
就需要信号捕获之后在处理方法中重新设定闹钟。
硬件产生的信号
硬件异常被硬件以某种方式被硬件检测到并通知内核,然后内核向当前进程发送适当的信号。例如当前进程执行了除 以0的指令,CPU的运算单元会产生异常,内核将这个异常解释 为SIGFPE信号发送给进程。再比如当前进程访问了非 法内存地址,,MMU会产生异常,内核将这个异常解释为SIGSEGV信号发送给进程。
如何理解除0错误
数据在cpu上进行计,cpu上由寄存器其中有一种状态寄存器。有对应的状态标记位如果发生错误os会自动进行计算之后的检测。这个状态是由cpu执行的由操作系统检测。而出现硬件异常一般会打印消息然后退出。但是不退出也不是不行不过即使不退出也没什么用。信号捕捉之后如果发生死循环这是此刻的寄存器还是处于错误状态没有进行复位。
如何理解野指针和越界问题
都必须通过地址找到目标位置语言上的地址都是虚拟地址将语言上的虚拟地址转换成物理地址。页表MMU(硬件)找到地址。而野指针和越界在mmu转化的时候一定会报错。