文章目录
0. 目标完成情况
- LeetCode两道题 ---- done
- csapp 异常控制流尽量看完吧 ---- 看完了,跳过了一些比较难的部分。
- 侯捷的基础视频再看一节 ---- 没看
1. 一天学习总结
今天起得很晚,上午几乎没有学习。今晚一定早睡。
1.1 LeetCode两道题
- 岛屿数量
这题我做过,我用的是广度优先遍历,而且这题是最普通的广度优先遍历,一定要用队列,要注意队列中节点的构造,还有入队之前要将相应位置置0. - 数字范围按位与
这题是将两个数字同步右移,直至相等,记录移动的次数,从而可以得出两个数字之间相等的最高的那几位,然后再移位回去就好了。
1.2 信号
信号是进程间通信的一种方式之一。信号是一条小消息,他标识着某种事件。信号可以由内核发送给进程,也可以有一个进程发送给另一个进程。在Linux下,信号有特定的几十种。
所谓发送信号,本质就是内核对目的进程的上下文做出某种改变,这个过程就称为发送信号。这个定义有点反常识,因为发送信号并不是发送方发出去一个东西。但是这个定义符合实际机理,我们的确需要区分“改变进程的状态”和“进程做出动作”之间的差别,前者是发送,后者是接收。
所谓接收信号,本质就是目的进程对信号的发送做出的某种动作。
所以发送和接受信号构成了进程间的一种通信方式。也就是说,发送进程可以告诉内核,我要发送一个信号给另一个进程,于是内核就对目的进程的上下文做出某种改变(这称为发送),然后目的进程根据这种改变,执行某种动作(这称为接收)。
1.2.1 如何发送信号?
有几种方式:
- 通过Linux自带的程序 /bin/kill , 可以给指定进程(组)发送某个信号。
- 通过C语言的 kill 函数 ,可以给指定进程组发送信号。
- 通过键盘,例如Ctrl+C。
- 还有一个忘了。今天记性贼差的感觉。
1.2.2 如何接受信号?
所谓接收信号,并不是直觉的接受信号,而是针对这个信号做出某个动作。
进程对一些信号有默认的动作。也就是说,我们不用关心如何接受信号的问题,他自己会自动接受。
但是我们也可以自定义接收方式,也就是自定义信号处理函数。------ 通过signal 函数。
1.3 非本地跳转
所谓非本地跳转,就是一种不同于函数和判断以及循环这样的跳转,这种跳转不一定会返回,返回的位置也很特别。
主要介绍了两个函数。
- setjmp函数。 这个函数可以保存当前进程的上下文到一个缓冲区env。此时setjmp的返回值为0.
- longjmp函数。这个函数可以将当前进程的上下文恢复为之前保存的env,然后跳转到setjmp函数的位置,并且让setjmp函数再次返回,这次setjmp函数的返回值是有longjmp指定的。
这两个函数组合使用,可以实现两个功能:
- 深层嵌套函数的快速返回。
- 和signal函数相结合,通过setjmp的不同返回值,实现程序的特殊跳转控制。
- 实现异常控制。例如在执行某语句之前,首先用setjmp保存状态,然后用signal设置对特定信号的处理函数,然后执行语句,一旦内核给该进程发送信号,且该进程捕获到了该信号(说白了就是调用信号处理程序),该进程就会进入异常(信号)处理程序,在处理程序的末尾,可以通过longjmp返回到setjmp保存的状态。从而不会因为某些信号的默认行为,而导致进程的异常终止。
setjmp和longjmp的组合,是C++和Java中的异常控制的底层原理。可以将catch子句视为setjmp,而讲throw语句视为longjmp。
这个地方还是不是很理解,可能是因为C++中的异常控制没怎么使用过吧。
1.4 try-catch-throw和if-else的区别的思考
我认为二者的最重大的区别在于逻辑的不同,if和else有一个判断,而try-catch是没有判断的。
- 在try语句中会直接执行可能会出现问题的语句,出现问题之后,再解决问题。
- if-else语句是坚决不会容忍出现问题的语句的。如果出现了问题,也就是说接收到了某个信号,例如除零错误信号,那么就将终止。
所以一个是防范于未然,一个是等待系统出现异常,然后catch,然后处理。而throw语句是用来检测异常的,或者说是用来增加一些本来不会被系统视为异常的信号,相应的,我们的catch语句可能就要多写一点。
此外还学习了程序的加载和执行, 主要是execve函数的执行过程。他和fork的区别在于execve不会创建新的进程,只是覆盖所在进程的执行代码。
2. 明日目标
- LeetCode 两道题
- 虚拟内存尽量看一半吧
- 侯捷C++看一个视频
- 开题报告回复老师