针对于嵌入式软件杂乱的知识点总结起来,提供给读者学习复习对下述内容的强化。
目录
20.server端监听端口,但还没有客户端连接进来,此时进程处于什么状态?
1.什么是进程?什么是线程?
进程是资源分配 的基本单位 ,它是程序执行时的一个实例,在程序运行时创建.
线程是程序执行 的最小单位,是进程的一个执行流,一个线程由多个线程组成的。
特点 | 进程 | 线程 |
---|---|---|
定义 | 独立的资源分配单位 | CPU调度的基本单位 |
地址空间 | 独立的地址空间 | 共享进程的地址空间 |
通信方式 | 通过IPC机制(如管道、消息队列等) | 通过共享内存直接通信 |
切换开销 | 高(需要切换上下文和资源) | 低(仅切换上下文) |
并发性 | 适合独立任务并行 | 适合同一任务的并发处理 |
创建开销 | 高 | 低 |
出错影响 | 一个进程的崩溃不影响其他进程 | 一个线程崩溃可能导致整个进程崩溃 |
在RTOS(实时操作系统)中,任务(Task)更接近于线程的概念,而不是进程。这是因为任务通常共享同一个地址空间(即它们没有像进程那样的独立地址空间),但每个任务有自己独立的运行上下文,如栈空间和程序计数器。
2.进程和线程有什么区别?
1.进程是资源分配 的最小单位。
2.线程是程序执行 的最小单位,也是处理器调度 的基本单位,但进程不是,两者均可并发执行。
3.进程有自己的独立地址 空间,每启动一个进程,系统就会为它分配地址空间,建立数据表来维护代码段、堆栈段和数据段,这种操作非常昂贵。而线程是共享进程中的数据,使用相同的地址空间,因此,CPU切换一个线程的花费远比进程小很多,同时创建一个线程的开销也比进程小很多。
4.线程之间的通信更方便,同一进程下的线程共享全局变量、静态变量等数据,而进程之间的通信需要以通信的方式(IPC)进行。不过如何处理好同步与互斥是编写多线程程序的难点。但是多进程程序更健壮,多线程程序只要有一个线程死掉,整个进程也跟着死掉了,而一个进程死掉并不会对另外一个进程造成影响,因为进程有自己独立的地址空间!!!! 。
5.进程切换时,消耗的资源大,效率低。所以涉及到频繁的切换时,使用线程要好于进程。同样如果,要求同时进行并且又要共享某些变量的并发操作,只能用线程不能用进程。
6.执行过程:每个独立的进程有一个程序运行的入口、顺序执行序列和程序入口 。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制。
7.线程执行开销小 ,但是不利于资源的管理和保护。线程适合在SMP机器(双CPU系统)上运行。进程执行开销大,但是能够很好的进行资源管理和保护,可以跨机器迁移。
特性 | 进程 | 线程 |
---|---|---|
定义 | 资源分配的最小单位 | 程序执行的最小单位 |
地址空间 | 独立 | 共享 |
切换开销 | 高 | 低 |
通信方式 | 复杂(IPC机制) | 简单(共享内存) |
健壮性 | 高 | 低 |
资源开销 | 创建、销毁、切换开销大 | 创建、销毁、切换开销小 |
适用场景 | 隔离性强,独立任务 | 频繁切换,共享数据的高并发任务 |
示例 | 浏览器的标签页独立进程 | 浏览器的渲染线程、网络线程 |
3.何时使用多进程,何时使用多线程?
对资源的管理和保护要求高 ,不限制开销和效率时 ,使用多进程。
要求效率高,频繁切换时 ,资源的保护管理要求不是很高时,使用多线程。
4.进程有几种状态?画一下进程状态转换图?
进程可以分为五个状态,分别是:
1.创建状态
2.就绪状态
3.运行状态
4.阻塞状态
5.终止状态
创建状态
一个应用程序从系统上启动,首先就是进入创建状态,需要获取系统资源创建进程管理块(PCBProcess Control Block)完成资源分配。
就绪状态
在创建状态完成之后,进程已经准备好,但是还未获得处理器资源,无法运行
运行状态
获取处理器资源,被系统调度,开始进入运行状态。如果进程的时间片用完了就进入就绪状态。
阻塞状态
在运行状态期间,如果进行了阻塞的操作,如耗时的!/0操作,此时进程暂时无法操作就进入到了阻塞状态,在这些操作完成后就进入就绪状态。
终止状态
进程结束或者被系统终止,进入终止状态
5.创建进程有哪几种方式?
创建进程的多种方式但凡是硬件,都需要有操作系统去管理,只要有操作系统,就有进程的概念,就需要有创建进程的方式,一些操作系统只为个应用程序设计,比如扫地机器人,一旦启动,所有的进程都已经存在。
而对于通用系统(跑很多应用程序),需要有系统运行过程中创建或撤销进程的能力,主要分为4种形式创建新的进程:
1.系统初始化 (查看进程 linux中用ps命令,windows中用任务管理器,前台进程负责与用户交互,后台运行的进程与用户无关,运行在后台并且只在需要时才唤醒的进程,称为守护进程,如电子邮件、web页面、新闻、打印)
2.一个进程在运行过程中开启了子进程 (如 nginx开启多进程,os.fork,subprocess Popen等)
3.用户的交互式请求,而创建一个新进程 (如用户用鼠标双击任意款软件图片:q微信暴风影音等)
4.一个批处理作业的初始化(只在大型机的批处理系统中应用)无论哪-种,新进程的创建都是由一个已经存在的进程执行了一个用于创建进程的系统调用而创建的。
6.进程间通信的方式有哪些?有什么优缺点?
1. 管道(Pipe)
特点:
半双工:数据只能单向流动。
父子关系:通常用于具有亲缘关系的进程之间通信(如父进程和子进程)。
匿名管道:没有名字,仅限于相关进程之间。
命名管道(FIFO):有名字,不要求进程有亲缘关系。
优点:
简单,适合父子进程通信。
系统提供的机制,开销较小。
缺点:
只能在本地使用。
数据方向有限(匿名管道单向)。
缓冲区有限,可能会阻塞读写。
2. 信号(Signal)
特点:
用于异步通信,发送信号以通知某些事件的发生。
信号可以中断目标进程的执行。
优点:
轻量级,适合简单的通知。
实时性较好。
缺点:
传输信息量有限,仅能传递信号的类型。
编程复杂,需要处理信号处理函数。
3. 消息队列(Message Queue)
特点:
按消息为单位进行通信。
消息可以被存储在队列中,直到接收方读取。
优点:
不要求进程有亲缘关系。
可以实现异步通信,消息按优先级排序。
缺点:
消息队列的大小有限。
消息需要拷贝两次,效率低于共享内存。
4. 共享内存(Shared Memory)
特点:
各进程直接共享一块内存区域。
是最快的通信方式之一。
优点:
高效,数据直接被访问,无需拷贝。
适合大数据量的通信。
缺点:
需要借助同步机制(如信号量)解决并发访问问题。
编程复杂度较高。
5. 信号量(Semaphore)
特点:
一种计数器,用于多进程同步或互斥。
不直接传递数据,而是协调资源的使用。
优点:
解决共享资源的同步问题。
可以实现跨进程的同步。
缺点:
不能传递实际的数据。
需要手动设计同步逻辑。
6. 套接字(Socket)
特点:
支持网络通信,可以在不同主机间通信。
分为流式套接字(TCP)和数据报套接字(UDP)。
优点:
功能强大,支持本地和远程通信。
通信范围广,适合分布式系统。
缺点:
编程复杂度高。
性能可能受网络环境影响。
7. 文件(File)
特点:
使用文件系统作为中介,通过读写文件进行通信。
优点:
简单直观,适合持久化数据。
通信过程容易追踪(通过文件内容)。
缺点:
通信效率低。
需要磁盘IO操作,开销较大。
方式 | 通信速度 | 数据传输 | 同步 | 适用场景 |
---|---|---|---|---|
管道 | 中 | 字节流 | 自动 | 父子进程间简单通信 |
信号 | 高 | 事件通知 | 自动 | 异步事件处理 |
消息队列 | 中 | 消息 | 自动 | 进程间按消息单位通信 |
共享内存 | 高 | 直接访问内存区域 | 手动(需同步) | 大数据量通信,速度要求高 |
信号量 | 中 | 无数据(同步工具) | 手动 | 资源竞争和同步 |
套接字 | 低(网络) | 字节流 | 手动(应用实现) | 网络通信、分布式系统 |
文件 | 低 | 文件内容 | 手动 | 数据持久化或简单通信 |
7.线程间同步方法有哪些?
现在流行的进程线程同步互斥的控制机制,其实是由最原始、最基本的4种方法(临界区、互斥量、信号量和事件)实现的。
1.临界区 :通过对多线程的串行化来访问公共资源或一段代码,速度快,适合控制数据访问。在任意时刻只允许一个线程访问共享资源,如果有多个线程试图访问共享资源,那么当有一个线程进入后,其他试图访问共享资源的线程将会被挂起,并一直等到进入临界区的线程离开,临界在被释放后,其他线程才可以抢占。
2.互斥量 :为协调对一个共亨资源的单独访问而设计,只有拥有互斥量的线程,才有权限去访问系统的公共资源,因为互斥量只有一个,所以能够保证资源不会同时被多个线程访问。互斥不仅能实现同一应用程序的公共资源安全共享,还能实现不同应用程序的公共资源安全共享。
3.信号量 :为控制一个具有有限数量的用户资源而设计。它允许多个线程在同一个时刻去访问同一个资源,但一般需要限制同一时刻访问此资源的最大线程数目
4.事件:用来通知线程有一些事件已发生,从而启动后继任务的开始。
8.什么是内核线程和用户线程?
用户线程 指不需要内核支持而在用户程序中实现的线程,其不依赖于操作系统核心,应用进程利用线程库提供创建、同步、调度和管理线程的函数来控制用户线程。不需要用户态/核心态切换,速度快,操作系统内核不知道多线程的存在,因此一个线程阻塞将使得整个进程(包括它的所有线程)阻塞。由于这里的处理器时间片分配是以进程为基本单位,所以每个线程执行的时间相对减少。
内核线程:由操作系统内核创建和撤销。内核维护进程及线程的上下文信息以及线程切换。一个内核线程由于I/0操作而阻塞,不会影响其它线程的运行。
9.内核线程和用户线程的区别?
1.内核支持线程是OS内核可感知的,而用户级线程是OS内核不可感知的。
2.用户级线程的创建、撤消和调度不需要OS内核的支持,是在语言(如ava)这一级处理的;而内核支持线程的创建、撤消和调度都需OS内核提供支持,而且与进程的创建、撤消和调度大体是相同的。
3.用户级线程执行系统调用指令时将导致其所属进程被中断,而内核支持线程执行系统调用指令时只导致该线程被中断。
4.在只有用户级线程的系统内,CPU调度还是以进程为单位,处于运行状态的进程中的多个线程,由用户程序控制线程的轮换运行;在有内核支持线程的系统内,CPU调度则以线程为单位,由OS的线程调度程序负责线程的调度。
5.用户级线程的程序实体是运行在用户态下的程序,而内核支持线程的程序实体则是可以运行在任何状态下的程序。
10.内核线程和用户线程有什么优缺点?
内核线程的优点:
当有多个处理机时,一个进程的多个线程可以同时执行。
缺点:
由内核进行调度。
用户线程的优点:
1.线程的调度不需要内核直接参与,控制简单。
2.可以在不支持线程的操作系统中实现。
- 创建和销毁线程、线程切换代价等线程管理的代价比内核线程少得多。
4.允许每个进程定制自己的调度算法,线程管理比较灵活。这就是必须自己写管理程序,与内核线程
的区别
5.线程能够利用的表空间和堆栈空间比内核级线程多,
6.同一进程中只能同时有一个线程在运行,如果有-一个线程使用了系统调用而阻塞,那么整个进程都会被挂起。另外,页面失效也会产生同样的问题。
缺点:
4.资源调度按照进程进行,多个处理机下,同一个进程中的线程只能在同一个处理机下分时复用
11.什么是僵尸进程,孤儿进程,守护进程?
僵尸进程 是一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵死进程。
孤儿进程 是因为父进程异常结束了,然后被1号进程init收养。
守护进程 是创建守护进程时有意把父进程结束,然后被1号进程init收养
区分: 一个正常运行的子进程,如果此刻子进程退出,父进程没有及时调用wait或waitpid收回子进程的系统资源,该进程就是僵尸进程,如果系统收回了,就是正常退出,如果一个正常运行的子进程,父进程退出了但是子进程还在,该进程此刻是孤儿进程,被init收养,如果父进程是故意被杀掉,子进程做相应处理后就是守护进程
12.僵尸进程有什么危害?
在进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。但是仍然为其保留一定的信息(包括进程号 PID,退出状态 the termination status ofthe process,运行时间 the amountof CPU time taken by the process 等)。直到父进程通过 wait/waitpid 来取时才释放。
如果进程不调用 wait/waitpid 的话 ,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的,如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程。
13.如何清理僵尸进程
僵尸进程的产生是因为父进程没有 wait() 子进程。所以如果我们自己写程序的话一定要在父进程中通过wait()来避免僵尸进程的产生。
当系统中出现了僵尸进程时,我们是无法通过 ki 命令把它清除掉的。但是我们可以杀死它的父进程让它变成孤儿进程,并进一步被系统中管理孤儿进程的进程收养并清理。
14.如何唤醒被阻塞的socket线程?
同步阻塞
等待锁的释放
等待阻塞
1.使用Thread.sleep造成的阻塞:时间结束后自动进入RUNNABLE状态
2.使用Thread.wait造成的阻塞:使用Thread.notify或者Thread.notifyAll唤醒
3.使用Thread.join造成的阻塞:等待上一个线程执行完后自动进入RUNNABLE状态
4.使用Thread.suspend造成的阻塞:使用Thread.resum唤醒
5.使用Locksupport.park造成的阻塞:使用Locksupport.unpark唤醒
6.使用LockSupport.parkNanos造成的阻塞:指定时间结束后,自动唤醒
7.使用Locksupport.parkUntil造成的阻塞:到达指定的时间,自动唤醒
15.如何确定当前线程是繁忙还是阻塞?
使用ps命令查看
16.空闲的进程和阻塞的进程状态会不会在唤醒的时候误判?
不会。每个进程有个进程控制块PCB,两种状态的进程分别处于两种队列。唤醒应该是找阻塞队列的进程。
17.请问就绪状态的进程在等待什么?
被调度使用cpu的运行权
18.如何实现线程池?
1.设置一个生产者消费者队列,作为临界资源
2.初始化n个线程,并让其运行起来,加锁去队列取任务运行
3.当任务队列为空的时候,所有线程阻寒
4.当生产者队列来了一个任务后,先对队列加锁,把任务挂在到队列上,然后使用条件变量去通知阳
塞中的一个线程
19.请你回答一下fork和vfork的区别?
对比项 | fork |
vfork |
---|---|---|
地址空间 | 子进程会复制父进程的地址空间(独立地址空间)。 | 子进程与父进程共享同一地址空间。 |
性能 | 由于复制地址空间,性能相对较低。 | 不复制地址空间,性能更高。 |
父进程执行状态 | 父进程和子进程可以并发运行。 | 父进程会挂起,直到子进程调用 exec() 或 exit() 。 |
子进程的行为 | 子进程是父进程的完整副本,包括变量、堆栈等。 | 子进程运行时会影响父进程的内存状态(因共享地址空间)。 |
用途 | 用于大部分场景,可靠性高。 | 用于立即调用 exec() 或快速退出的场景。 |
实现方式 | 通过写时复制(Copy-On-Write)优化内存使用。 | 无需复制内存,直接共享父进程内存。 |
内存安全性 | 子进程的修改不会影响父进程。 | 子进程的修改会影响父进程(共享内存)。 |
20.server端监听端口,但还没有客户端连接进来,此时进程处于什么状态?
最普通的Server模型,则处于阻塞状态;如果使用IO复用中epoll、select等,则处于运行状态。