面试基础知识 操作系统

进程和线程的基本概念和区别

线程是进程的子任务,实现进程内部的并发,每个线程完成不同的任务,但是共享同一操作地址。
区别:

  1. 进程是资源分配的最小单位,线程是CPU调度的最小单位
  2. 一个线程只能属于一个进程,一个进程可以拥有多个线程
  3. 进程在执行过程中拥有独立内存,多个线程共享内存
  4. 进程创建销毁开销大,线程开销小
  5. 一个进程崩溃,不会对其他进程产生影响;而一个线程崩溃,会让同一进程内的其他线程也死掉。

进程间的通信方式

  1. 管道通信
    1)管道PIPE通信:半双工,只能在有亲缘关系的进程之间通信
    2)管道FIFO通信:可以在无关的进程之间交换数据
  2. 消息队列:具有写权限得进程可以按照一定得规则向消息队列中添加新信息;对消息队列有读权限得进程则可以从消息队列中读取信息。消息队列独立于发送与接收进程,进程终止时,消息队列及其内容并不会被删除。
  3. 信号量:是一个计数器,用来记录当前可用设备的资源数。信号量用于实现进程间的互斥和同步,而不是用于储存进程间的通信数据,若要在进程间传递数据需要结合共享内存
  4. 共享内存:它使得多个进程可以访问同一块内存空间
  5. 套接字Socket:不同主机之间的进程通信

线程间的通信方式:

  1. 临界区:通过多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问
  2. 锁机制:
    互斥锁:提供了以排他方式防止数据结构被并发修改的方法。
    读写锁:允许多个线程同时共享数据,而对写操作是互斥的。
  3. 信号(Wait/notify):通过通知操作来保持多线程同步

Linux虚拟内存

为了防止不同进程在同一时刻对物理内存的争夺。进程创建的时候,其实只是创建了虚拟内存和磁盘文件的映射,程序运行的时候才会复制数据
虚拟内存的好处:

  1. 扩大地址空间
  2. 内存保护:每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方
  3. 进程通信:可采用虚存共享的方式实现进程间通信。
  4. 在内存中可以保留多个进程,提高系统并发度

fork和vfork的区别

  1. fork():子进程拷贝父进程的数据段,代码段
    vfork():子进程与父进程共享数据段
  2. fork():父子进程的执行次序不确定
    vfork() 保证子进程先运行,在调用exec 或exit 之前与父进程数据是共享的,在它调用exec或exit 之后父进程才可能被调度运行。
  3. vfork() 保证子进程先运行,在她调用exec 或exit 之后父进程才可能被调度运行。如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁。

并发和并行

并发(concurrency):指宏观上看起来两个程序在同时运行,比如说在单核cpu上的多任务。但是从微观上看两个程序的指令是交织着运行的,你的指令之间穿插着我的指令,我的指令之间穿插着你的,在单个周期内只运行了一个指令。这种并发并不能提高计算机的性能,只能提高效率。

并行(parallelism):指严格物理意义上的同时运行,比如多核cpu,两个程序分别运行在两个核上,两者之间互不影响,单个周期内每个程序都运行了自己的指令,也就是运行了两条指令。这样说来并行的确提高了计算机的效率。所以现在的cpu都是往多核方面发展。

死锁发生的条件以及如何解决死锁

死锁是指两个或两个以上进程在执行过程中,因争夺资源而造成的下相互等待的现象。死锁发生的四个必要条件如下:

  1. 互斥条件:进程对所分配到的资源不允许其他进程访问,若其他进程访问该资源,只能等待,直至占有该资源的进程使用完成后释放该资源;
  2. 请求和保持条件:进程获得一定的资源后,又对其他资源发出请求,但是该资源可能被其他进程占有,此时请求阻塞,但该进程不会释放自己已经占有的资源
  3. 不可剥夺条件:进程已获得的资源,在未完成使用之前,不可被剥夺,只能在使用后自己释放
  4. 环路等待条件:进程发生死锁后,必然存在一个进程-资源之间的环形链

解决死锁的方法即破坏上述四个条件之一,主要方法如下:

  1. 资源一次性分配:从而剥夺请求和保持条件
  2. 可剥夺资源:即当进程新的资源未得到满足时,释放已占有的资源,从而破坏不可剥夺的条件
  3. 资源有序分配法:系统给每类资源赋予一个序号,每个进程按编号递增的请求资源,释放则相反,从而破坏环路等待的条件

虚拟地址、逻辑地址、线性地址、物理地址

逻辑地址 -->(分段机制) 线性地址 -->(分页机制) 物理地址。在Linux下,逻辑地址与线性地址总是一致,即逻辑地址的偏移量字段的值与线性地址的值总是相同的
段式管理——逻辑地址转线性地址
逻辑地址由两部份组成,【段标识符:段内偏移量】
段起始地址+ 段内偏移量 = 线性地址
页式管理——线性地址转物理地址

Linux锁机制(线程同步)

互斥锁:mutex,用于保证在任何时刻,都只能有一个线程访问该对象。当获取锁操作失败时,线程会进入睡眠,等待锁释放时被唤醒。
读写锁:rwlock,分为读锁和写锁。处于读操作时,可以允许多个线程同时获得读操作。但是同一时刻只能有一个线程可以获得写锁。其它获取写锁失败的线程都会进入睡眠状态,直到写锁释放时被唤醒。
自旋锁:spinlock,在任何时刻同样只能有一个线程访问对象。但是当获取锁操作失败时,不会进入睡眠,而是会在原地自旋,直到锁被释放。这样节省了线程从睡眠状态到被唤醒期间的消耗,在加锁时间短暂的环境下会极大的提高效率。但如果加锁时间过长,则会非常浪费CPU资源。
RCU:即read-copy-update,在修改数据时,首先需要读取数据,然后生成一个副本,对副本进行修改。修改完成后,再将老数据update成新的数据。使用RCU时,读者几乎不需要同步开销,既不需要获得锁,也不使用原子指令,不会导致锁竞争,因此就不用考虑死锁问题了。而对于写者的同步开销较大,它需要复制被修改的数据,还必须使用锁机制同步并行其它写者的修改操作。在有大量读操作,少量写操作的情况下效率非常高。

内存溢出和内存泄漏

  1. 内存溢出指程序申请内存时,没有足够的内存供申请者使用。内存溢出就是你要的内存空间超过了系统实际分配给你的空间,此时系统相当于没法满足你的需求,就会报内存溢出的错误
  2. 内存泄漏:内存泄漏是指由于疏忽或错误造成了程序未能释放掉不再使用的内存的情况
    内存泄漏有三种:
    1)堆内存泄漏:new后忘记delete
    2)系统资源泄漏:handle或Socket没有使用响应的函数释放掉
    3)没有将基类的析构函数定义为虚函数,当基类指针指向子类对象时,如果基类的析构函数不是virtual,那么子类的析构函数将不会被调用

五种IO模型

1.阻塞IO:调用者调用了某个函数,等待这个函数返回,期间什么也不做,不停的去检查这个函数有没有返回,必须等这个函数返回才能进行下一步动作
2.非阻塞IO:非阻塞等待,每隔一段时间就去检测IO事件是否就绪。没有就绪就可以做其他事。
3.信号驱动IO:信号驱动IO:linux用套接口进行信号驱动IO,安装一个信号处理函数,进程继续运行并不阻塞,当IO时间就绪,进程收到SIGIO信号。然后处理IO事件。
4.IO复用:多路转接IO:linux用select/poll函数实现IO复用模型,这两个函数也会使进程阻塞,但是和阻塞IO所不同的是这两个函数可以同时阻塞多个IO操作。而且可以同时对多个读操作、写操作的IO函数进行检测。知道有数据可读或可写时,才真正调用IO操作函数
5.异步IO:linux中,可以调用aio_read函数告诉内核描述字缓冲区指针和缓冲区的大小、文件偏移及通知的方式,然后立即返回,当内核将数据拷贝到缓冲区后,再通知应用程序。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值