【面试总结】小灰灰求职进行曲(四)操作系统

操作系统系统笔记整理

1 进程间通信方式

进程间8种通信方式详解

进程通信:
每个进程各自有不同的用户地址空间,任何一个进程的全局变量在另一个进程中都看不到,所以进程之间要交换数据必须通过内核,在内核中开辟一块缓冲区,进程A把数据从用户空间拷到内核缓冲区,进程B再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信

  • 管道( pipe )
  • 消息队列(message queue )
  • 信号量(semophore )
  • 共享内存(shared memory)
  • 套接字(socket)

在这里插入图片描述

2 多线程的通讯和同步

多线程的通讯
在这里插入图片描述

  • 上下文切换时(这里指进程间的切换)不需要切换数据区和堆

  • 可以利用数据区和堆交换数据

  • 线程有自己的栈空间程序计数器(PC指针)

JVAV中线程通信

  • ① volatile

所有volatile修饰的变量一旦被某个线程更改,必须立即刷新到主内存
所有volatile修饰的变量在使用之前必须重新读取主内存的值

  • ② 等待/通知机制(wait和notify)

等待通知机制是基于wait和notify方法来实现的,在一个线程内调用该线程锁对象的wait方法,线程将进入等待队列进行等待直到被通知或者被唤醒

为什么要必须获取锁?
因为调用wait方法时,必须要先释放锁,如果没有持有锁将会抛出异常。

  • ③ join方式

join其实合理理解成是线程合并,当在一个线程调用另一个线程的join方法时当前线程阻塞等待被调用join方法的线程执行完毕才能继续执行,所以join的好处能够保证线程的执行顺序,但是如果调用线程的join方法其实已经失去了并行的意义,虽然存在多个线程,但是本质上还是串行的,最后join的实现其实是基于等待通知机制的。

  • ④ threadLocal方式

threadLocal方式的线程通信,不像以上三种方式是多个线程之间的通信,它更像是一个线程内部的通信,将当前线程和一个map绑定,在当前线程内可以任意存取数据,减省了方法调用间参数的传递。

多线程的同步(如何解决线程安全问题)

线程间同步的三种方法

  • 互斥锁(mutex)
  • 读写锁
  • 条件变量(condition) (条件变量是用来等待而不是用来上锁的)
  • 信号量(semophore )

如何解决多线程之间线程安全问题? 答:使用多线程之间同步synchronized或使用锁(lock)

3 Linux 多线程环境下 线程joinable状态和unjoinable状态

这里主要讨论这两种状态下,线程终止以及资源释放的问题

linux线程中,pthread有两种状态joinable状态和unjoinable状态。

joinable状态下,当线程函数自己返回退出时或pthread_exit时都不会释放线程所占用堆栈和线程描述符。只有当你调用了pthread_join之后这些资源才会被释放,这是需要main函数或者其他线程去调用pthread_join函数。

unjoinable状态的线程,这些资源在线程函数退出时或pthread_exit自动会被释放。设置unjoinable状态设置有两种办法 一是可以在pthread_create时指定,二是线程创建后在线程中pthread_detach自己 pthread_detach(pthread_self()),状态改为unjoinable状态,确保资源的释放

4 什么是协程

协程是比线程更小的一种执行单元,你可以认为是轻量级的线程,之所以说轻,其中一方面的原因是协程所持有的栈比线程要小很多,java当中会为每个线程分配1M左右的栈空间,而协程可能只有几十或者几百K栈主要用来保存函数参数、局部变量和返回地址等信息
我们知道,而线程的调度是在操作系统中进行的,而协程调度则是在用户空间进行的,是开发人员通过调用系统底层的执行上下文相关api来完成的,有些语言,比如nodejs、go在语言层面支持了协程,而有些语言,比如C,需要使用第三方库才可以拥有协程的能力。
由于线程是操作系统的最小执行单元,因此也可以得出,协成是基于线程实现的,协程的创建、切换、销毁都是在某个线程中来进行的。

使用协程是因为线程的切换成本比较高,而协程在这方面很有优势

5 自旋锁和互斥锁的区别

自旋锁是一种互斥锁的实现方式而已,相比一般的互斥锁会在等待期间放弃cpu,自旋锁(spinlock)则是不断循环并测试锁的状态,这样就一直占着cpu

互斥锁:用于保护临界区,确保同一时间只有一个线程访问数据 。对共享资源的访问,先对互斥量进行加锁,如果互斥量已经上锁,调用线程会阻塞,直到互斥量被解锁。在完成了对共享资源的访问后,要对互斥量进行解锁。

自旋锁:与互斥量类似,它不是通过休眠使进程阻塞,而是在获取锁之前一直处于忙等(自旋)阻塞状态。用在以下情况:锁持有的时间短,而且线程并不希望在重新调度上花太多的成本。“原地打转”。

自旋锁与互斥锁的区别:线程在申请自旋锁的时候,线程不会被挂起,而是处于忙等的状态。

6 内存泄漏检测工具 mtrace

在一般的linux发行版中,有一个自带的工具可以很方便的替你完成这些事,这个工具就是mtrace.

mtrace其实是GNU扩展函数,用来跟踪malloc

mtrace为内存分配函数(malloc, realloc, memalign, free)安装hook函数。这些hook函数记录内存的申请和释放的trace信息。

在程序中,这些trace信息可以被用来发现内存泄漏和释放不是申请的内存。
当调用mtrace,mtrace会检查环境变量MALLOC_TRACE。该环境变量应该包含记录trace信息的文件路径。如果文件可以被成功打开,它的大小被截断为0。如果MALLOC_TRACE没有设置,或者设置的文件不可用或者不可写,那么将不会安装hook函数,mtrace不生效。

7 虚拟内存与物理内存关系

虚拟内存与物理内存的联系与区别

8 僵尸进程和孤儿进程

孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。

僵尸进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。

9 动态链接库和静态链接库

库是写好的现有的,成熟的,可以复用的代码。现实中每个程序都要依赖很多基础的底层库,不可能每个人的代码都从零开始,因此库的存在意义非同寻常

库有两种:静态库(.a、.lib)动态库(.so、.dll)

静态链接库

在这里插入图片描述

  • 静态库对函数库的链接是放在编译时期完成
  • 程序在运行时与函数库再无瓜葛,移植方便
  • 浪费空间和资源,因为所有相关的目标文件都与牵连的函数库被链接成一个可执行文件
  • 静态库对程序的更新部署发布都带来麻烦。(全量更新

链接阶段,会将汇编生成的目标文件.o引用到的库一起链接打包到可执行文件中。因此对应的链接方式称为静态链接。

动态链接库

在这里插入图片描述

  • 动态库把对一些库函数的链接载入推迟到程序运行的时期
  • 可以实现进程之间的资源共享。(因此动态库也称为共享库)
  • 将一些程序升级变得简单
  • 甚至可以真正做到链接载入完全由程序员在程序代码中控制(显示调用

动态库在程序编译时并不会被连接到目标代码中,而是在程序运行是才被载入。不同的应用程序如果调用相同的库,那么在内存里只需要有一份该共享库的实例规避了空间浪费问题
动态库在程序运行是才被载入,也解决了静态库对程序的更新、部署和发布页会带来麻烦。用户只需要更新动态库即可,增量更新

10 进程的常见状态?以及各种状态之间的转换条件

在这里插入图片描述
就绪态 to 运行态:获取到CPU时间片
运行态 to 就绪态:执行完毕进程的CPU时间片
运行态 to 阻塞态:等待IO或事件完成
阻塞态 to 就绪态:就绪IO或事件完成

11
12
13
14
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值