操作系统

C

malloc 动态内存分配

malloc的全称是memory allocation,中文名为动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址

calloc

clear allocation,中文名为动态内存分配并清零如果分配成功则返回指向被分配内存的指针**(此空间中的初始值为0)**,否则返回空指针NULL

realloc

动态内存调整

先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将mem_address返回,如果空间不够,先按照newsize指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来mem_address所指内存区域(原来的指针会自动释放,不需要再使用free),同时返回新分配的内存区域的首地址。重新分配成功返回指向被分配内存的指针,否则返回空指针NULL。

free

使用malloc,calloc,realloc函数进行内存分配后要使用free(起始地址的指针) 对内存进行释放

在C++中是new delete

进程管理

进程切换

img

进程切换

上图展示了进程切换中几个最重要的步骤:

  1. 当一个程序正在执行的过程中, 中断(interrupt) 或 系统调用(system call) 发生可以使得 CPU 的控制权会从当前进程转移到操作系统内核。
  2. 操作系统内核负责保存进程 i 在 CPU 中的上下文(程序计数器, 寄存器)到 PCBi (操作系统分配给进程的一个内存块)中。
  3. 从 PCBj 取出进程 j 的CPU 上下文, 将 CPU 控制权转移给进程 j , 开始执行进程 j 的指令。

孤儿进程和僵尸进程的区别?

https://www.cnblogs.com/Anker/p/3271773.html

子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

孤儿进程:父进程执行完或被终止,但是它仍在运行。孤儿进程将会被init进行进程号为1的进程收集。

僵尸进程:是指执行完成后,但是在进程控制块PCB中仍然还有一个表项。一般是由一个进程fork创建子进程,如果子进程退出,但是父进程没有调用wait或waitpid获取子进程的信息,那么子进程的进程描述符仍然在PCB中,这种进程称为姜丝进程。

每个进程再exit()之后都会成为僵尸进程,但是父进程调用wait后便可以删除PCB中的信息。

僵尸进程危害?

孤儿进程会被init进程收集,不会产生危害。

僵尸进程:但是如果父进程没有调用wait或者waitpid来获取子进程结束的信息,那么PCB中的信息将不会被释放,进程号一直被占用。

如何解决?

(1)通过信号,子进程结束的时候向父进程发送一个信号,在信号处理函数中调用wait进行处理僵尸进程。

(2)fork两次原理是将子进程成为孤儿进程,从而其的父进程变为init进程,通过init进程可以处理僵尸进程。

守护进程

守护进程是一个在后台运行并且不受任何终端控制的进程。

如何创建守护进程?

(1)创建子进程,终止父进程

由于守护进程是脱离控制终端的,因此首先创建子进程,终止父进程,使得程序在shell终端里造成一个已经运行完毕的假象。之后所有的工作都在子进程中完成,而用户在shell终端里则可以执行其他的命令,从而使得程序以僵尸进程形式运行,在形式上做到了与控制终端的脱离。

(2)在子进程中创建新会话

这个步骤是创建守护进程中最重要的一步,在这里使用的是系统函数setsid。

setsid函数用于创建一个新的会话,并担任该会话组的组长。调用setsid仃三个作用:让进程摆脱原会话的控制、让进程摆脱原进程组的控制和让进程摆脱原控制终端的控制。

在调用fork函数时,子进程全盘拷贝父进程的会话期(session,是一个或多个进程组的集合)、进程组、控制终端等,虽然父进程退出了,但原先的会话期、进程组、控制终端等并没有改变,因此,那还不是真正意义上使两者独立开来。setsid函数能够使进程完全独立出来,从而脱离所有其他进程的控制。

(3)改变工作目录

使用fork创建的子进程也继承了父进程的当前工作目录。由于在进程运行过程中,当前目录所在的文件系统不能卸载,因此,把当前工作目录换成其他的路径,如“/”或“/tmp”等。改变工作目录的常见函数是chdir。

(4)重设文件创建掩码

文件创建掩码是指屏蔽掉文件创建时的对应位。由于使用fork函数新建的子进程继承了父进程的文件创建掩码,这就给该子进程使用文件带来了诸多的麻烦。因此,把文件创建掩码设置为0,可以大大增强该守护进程的灵活性。设置文件创建掩码的函数是umask,通常的使用方法为umask(0)。

(5)关闭[文件描述符]

用fork新建的子进程会从父进程那里继承一些已经打开了的文件。这些被打开的文件可能永远不会被守护进程读或写,但它们一样消耗系统资源,可能导致所在的文件系统无法卸载

syslogd

进程间通信的7种方式

第一类:传统的Unix通信机制

  1. 管道/匿名管道(pipe)

管道的实质:
管道的实质是一个内核缓冲区,进程以先进先出的方式从缓冲区存取数据,管道一端的进程顺序的将数据写入缓冲区,另一端的进程则顺序的读出数据。该缓冲区可以看做是一个循环队列,读和写的位置都是自动增长的,不能随意改变,一个数据只能被读一次,读出来以后在缓冲区就不复存在了。当缓冲区读空或者写满时,有一定的规则控制相应的读进程或者写进程进入等待队列,当空的缓冲区有新数据写入或者满的缓冲区有数据读出来时,就唤醒等待队列中的进程继续读写。

  1. 有名管道(FIFO)

    有名管道 (named pipe) : 有名管道也是半双工的通信方式,但是它允许无亲缘关系进程间的通信。

  2. 信号(Signal)

    ​ 信号 ( sinal ) : 信号是一种比较复杂的通信方式,用于通知接收进程某个事件已经发生。

  3. 消息(Message)队列

    消息队列( message queue ) : 消息队列是由消息的链表,存放在内核中并由消息队列标识符标识。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

  4. 共享内存(share memory)

    共享内存( shared memory ) :共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的 IPC 方式,它是针对其他进程间通信方式运行效率低而专门设计的。它往往与其他通信机制,如信号两,配合使用,来实现进程间的同步和通信。

  5. 信号量(semaphore)

    信号量( semophore ) : 信号量是一个计数器,可以用来控制多个进程对共享资源的访问。它常作为一种锁机制,防止某进程正在访问共享资源时,其他进程也访问该资源。因此,主要作为进程间以及同一进程内不同线程之间的同步手段。

  6. 套接字(socket)

    可用于不同机器间的进程通信。

linux底层是怎么创建线程的

https://blog.csdn.net/melody157398/article/details/104912317

0号进程是什么东西

Linux中的0号进程和1号进程

系统允许一个进程创建新进程,新进程即为子进程,子进程还可以创建新的子进程,形成进程树结构模型。整个linux系统的所有进程也是一个树形结 构。树根是系统自动构造的,即在内核态下执行的0号进程,它是所有进程的祖先。由0号进程创建1号进程(内核态),1号负责执行内核的部分初始化工作及进 行系统配置,并创建若干个用于高速缓存和虚拟主存管理的内核线程。随后,1号进程调用execve()运行可执行程序init,并演变成用户态1号进程, 即init进程。它按照配置文件/etc/initab的要求,完成系统启动工作,创建编号为1号、2号…的若干终端注册进程getty

进程调度的几种方式

  1. 先来先服务 有利于长作业,不利于短作业

    ​ 最短作业优先 短作业先行,长作业有可能长时间无法执行

    短作业优先

  2. 带有优先级的 抢占式和非抢占式,

    每个进行都有一个优先级,系统会先给优先级高的分配,对于抢占式的,如果当前进程正在执行,然后来了一个优先级高的,当前进程就阻塞,先给优先级高的执行;非抢占的就是先执行完当前这个在给优先级高的执行

  3. 最短作业优先

  4. 时间片轮转

    ​ 每个进程都执行一段时间 按FCFS排队,比较重要的是如何确定时间片长度;

  5. 优先级队列

  6. 多级队列 将上面的算法都结合到了一起

    ​ 有很多优先级不同的队列,每个优先级执行的时间片长度也不同,优先级越低,时间片越长。当一个进程到来时,先进入第一队列,如果在当前时间段没有运行完,则进入第二队列,然后依次往下。。。当且仅当高优先级处理完后才处理低优先级的队列。

https://www.cnblogs.com/Blog-day/p/My_Blog_Days1-11.html

操作系统的吧,进程、线程和协程分别是什么以及他们之间的关系

(自己整理一下答案,到时候就会说了)

32、64位系统有什么区别

32位和64位表示CPU一次能处理的最大位数

32位系统的最大寻址空间是2的32次方=4294967296(bit)= 4(GB)左右;

64位系统的最大寻址空间为2的64次方=4294967296(bit)的32次方,数值大于1亿GB

内存管理

什么是虚拟内存?

虚拟内存的目的是为了让物理内存扩充成更大的逻辑内存,从而让程序获得更多的可用内存。

内存分配方式

页式、段式、段页式

段页式系统访存次数

3次 段表->页地址->页表->地址 ->访问

为了访存的次数不这么多,在地址变换机构中增设一个高速缓冲寄存器,从中得到相应页的物理块号。

页面置换算法

OPT最佳,因为不可能向后预知,无法实现

LRU 最近最少未使用

FIFO先进先出

LFU最不长使用算法

死锁

死锁,发生的条件以及如何避免?

1**)互斥条件:**指进程对所分配到的资源进行排它性使用,即在一段时间内某资源只由一个进程占用。如果此时还有其它进程请求资源,则请求者只能等待,直至占有资源的进程用毕释放。

2**)请求和保持条件:**指进程已经保持至少一个资源,但又提出了新的资源请求,而该资源已被其它进程占有,此时请求进程阻塞,但又对自己已获得的其它资源保持不放。

3**)不剥夺条件:**指进程已获得的资源,在未使用完之前,不能被剥夺,只能在使用完时由自己释放。

4**)环路等待条件:**指在发生死锁时,必然存在一个进程——资源的环形链,即进程集合{P0,P1,P2,···,Pn}中的P0正在等待一个P1占用的资源;P1正在等待P2占用的资源,……,Pn正在等待已被P0占用的资源。

如何避免?

通过哲学家就餐问题分析

杀掉一个进程 -9 代表什么(强制) 还有什么其他参数使用kill命令后,操作系统是如何通知进程的

虚拟内存,虚地址实地址

磁盘调度

磁盘调度算法

FIFO

最短寻道时间优先

电梯算法

其余

系统调用是什么

系统调用(英语:system call),又称为系统呼叫,指运行在使用者空间的程序操作系统内核请求需要更高权限运行的服务。系统调用提供了用户程序与操作系统之间的接口(即系统调用是用户程序和内核交互的接口)。

  操作系统中的状态分为管态(核心态)和目态(用户态)。大多数系统交互式操作需求在内核态执行。如设备IO操作或者进程间通信。特权指令:一类只能在核心态下运行而不能在用户态下运行的特殊指令。不同的操作系统特权指令会有所差异,但是一般来说主要是和硬件相关的一些指令。用户程序只在用户态下运行,有时需要访问系统核心功能,这时通过系统调用接口使用系统调用。

危险的指令被包装成系统调用,用户程序只能调用而无权自己运行那些危险的指令。另外,计算机硬件的资源是有限的,为了更好的管理这些资源,所有的资源都由操作系统控制,进程只能向操作系统请求这些资源。操作系统是这些资源的唯一入口,这个入口就是系统调用。

两个进程如何访问临界区?

1.一个turn 标志哪一个进入 (问题:只能ABABABAB的形式)

2.设置flag[2] flag[0]表示A flag[1]表示B能否进入{
这时候有两种情况 先设置true还是先判断

​ 先判断有可能两个一起进入

​ 先设置有可能两个都进不去

​ }

3.flag[2]+turn

​ 设置flag 设置turn=另外一个 判断 flag&&turn==另外一个

​ 结束后设置flag

1
2
3
4
5
6
//flag[2]  turn
do{


}while(true);

BIO

同步阻塞IO :从系统调用开始一直到系统调用结束一直在阻塞。

阻塞时间太久,基本上会为每一个连接IO分配一个线程,不能处理高并发的情况。

image-20210421104956983

NIO

同步非阻塞IO: 系统调用开始后一直轮询数据是否准备好,如果准备好了就拷贝数据。

需要大量的轮询操作,占用大量的CPU时间

image-20210421105031788

IO多路复用

同步IO多路复用:线程发起select调用后,询问内核数据是否就绪,等内核准备好了以后用户线程在发起read调用。

需要不断select轮询,但是它可以通过一个线程处理成千上万个连接。

使用select的优势在于可以等待多个描述符就绪

image-20210421105400836

信号驱动IO

调用后会立即返回,然后再数据准备好的时候会返回一个信号

image-20210421105506866

AIO

异步IO: 通过通知回调机制完全不阻塞.对于异步来说,内核是调用的发起方

image-20210421105617920

epoll(基于事件的轮询) 也是Reactor设计模式

效率提升,不是轮询的方式,不会随着FD数目的增加效率下降。只有活跃可用的FD才会调用callback函数;即Epoll最大的优点就在于它只管你“活跃”的连接,而跟连接总数无关,因此在实际的网络环境中,Epoll的效率就会远远高于select和poll。

Select poll 和epoll的区别?

select使用数组 ,有1024的最大连接限制

poll使用链表没有最大连接限制

传统select/poll的另一个致命弱点就是当你拥有一个很大的socket集合,由于网络得延时,使得任一时间只有部分的socket是”活跃” 的,而select/poll每次调用都会线性扫描全部的集合,导致效率呈现线性下降。

epoll使用“事件”的就绪通知方式,通过epoll_ctl注册fd,一旦该fd就绪,内核就会采用类似callback的回调机制来激活该fd。

Select、Poll、Epoll详解

https://www.jianshu.com/p/722819425dbd