嵌入式面试专题—进程线程

目录

1.1 进程线程基本概念

1.1.1什么是进程,线程,彼此有什么区别⭐⭐⭐⭐⭐

1.1.2多进程、多线程的优缺点⭐⭐⭐⭐

1.1.3什么时候用进程,什么时候用线程⭐⭐⭐

1.1.4多进程、多线程同步(通信)的方法⭐⭐⭐⭐

(1)线程间的通信方式:

(2)进程间的通信方式

1.1.5进程的空间模型⭐⭐⭐

1.1.6一个进程可以创建多少线程,和什么有关⭐⭐

1.1.7进程线程的状态转换图 什么时候阻塞,什么时候就绪⭐⭐

(1)进程有5种状态

(2)线程有6种状态

1.1.8父进程、子进程的关系⭐⭐⭐⭐⭐

1.1.9什么是进程上下文、中断上下文⭐⭐

1.2 并发(同步,互斥),异步,阻塞,非阻塞的理解

1.2.1并发,同步,互斥,异步,阻塞,非阻塞的理解⭐⭐⭐⭐⭐

1.2.2什么是线程同步和互斥⭐⭐⭐⭐⭐

1.2.3线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?⭐⭐⭐

1.3 孤儿进程、僵尸进程、守护进程的概念

1.3.1 基本概念 ⭐⭐

1.3.2 如何创建守护进程:⭐⭐

1.3.3 正确处理孤儿进程、僵尸进程的方法⭐⭐⭐⭐⭐

(1)僵尸进程的处理方法:

(2)孤儿进程的处理方法:

补充:

1、防止线程之间相互竞争资源的方法。

2、管道和命名管道的区别

3、I/O多路复用

4、Fork函数


1.1 进程线程基本概念

1.1.1什么是进程,线程,彼此有什么区别⭐⭐⭐⭐⭐

进程:指在系统中正在运行的一个应用程序,程序一旦运行就是进程。也指程序执行时的一个实例。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位

线程:系统任务调度的基本/最小单元,或者说进程之内独立执行的一个单元执行流。一个进程可有多个线程。

区别: 进程是系统中资源分配的基本单位,线程是系统任务调度的基本/最小单位。

进程具有独立的空间地址,一个进程崩溃后,在保护模式下不会对其他进程产生影响,但线程共享本进程的地址空间,一个线程崩溃=整个进程死掉。

线程共享本进程的资源如内存、I/Ocpu等,不利于资源的管理和保护,而进程之间的资源是独立的,能很好的进行资源管理和保护。

④进程有一个程序运行的入口、顺序执行序列和程序出口,执行开销大。但是线程不能独立执行,必须依存在应用程序中,由应用程序提供多个线程执行控制,执行开销小线程只是一个进程的不同执行路径,线程有自己的堆栈和局部变量。

1.1.2多进程、多线程的优缺点⭐⭐⭐⭐

多进程优点:①每个进程互相独立,不影响主程序的稳定性;②可以减少线程加锁/解锁的影响,极大提高性能;③通过增加CPU,就可以容易扩充性能;

多进程缺点:逻辑控制复杂,需要和主程序交互;②多进程调度开销比较大;③需要跨进程边界,不适合大数据量的传送;

多线程优点:线程消耗的资源比进程少,程序的运行速度更快所有线程可以共享内存和变量等;程序逻辑和控制方式简单无需跨进程边界;

多线程缺点:①一个线程崩溃会影响整个程序的稳定性多线程需要更多的内存空间,同时多线程的调度需要消耗较多的CPU;③线程间的同步和加锁控制麻烦

1.1.3什么时候用进程,什么时候用线程⭐⭐⭐

① 涉及到频繁创建销毁、频繁的切换和需要大量计算时,使用线程

② 要求同时进行且又要共享某些变量的并行操作时,使用线程

③ 多机分布(分布内存,多个处理机CPU)用进程,多核(共享内存,多个内核)分布用线程。CPU系统使用效率上线程占优。

需要稳定安全时,选择进程,需要速度时,选择线程

1.1.4多进程、多线程同步(通信)的方法⭐⭐⭐⭐

1)线程间的通信方式:

线程间的通信目的主要是用于线程同步,所以线程没有像进程通信中的用于数据交换的通信机制。主要包括互斥锁、读写锁、条件变量、信号量和信号

互斥锁(也叫临界区):提供了以排他方式防止数据结构被并发修改的方法。

读写锁(锁机制):允许多个线程同时读共享数据,而对写操作是互斥的。

条件变量(锁机制,互斥锁的一个加强):以原子的方式阻塞进程,直到某个特定条件为真为止。对条件的测试是在互斥锁的保护下进行的。条件变量始终与互斥锁一起使用。

信号量机制:信号量是一个计数器,用于限制进程资源可以被多少个线程共享

信号机制:信号的本质是软件层次上对中断的一种模拟

2)进程间的通信方式

进程间通信包括本地进程间通信网络进程间通信。网络进程间通信:不同计算机的进程间通信,是基于网络套接字(socket)进程的通信。本地进程间通信:同一台计算机系统中各进程间的通信,包括五种:管道、命名管道、消息队列、共享内存和信号量。

管道:管道是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进程关系。

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

(高级管道:将另一个程序当做一个新的进程在当前程序中启动,则它算是当前程序的子进程,这种方式是高级管道方式)

消息队列:消息队列是由消息组成的链表,存放在内核中并由消息队列标识符标识,可以从一个进程向另外一个进程发送一个带有类型的数据块,属于全双工通信。消息队列克服了信号传递信息少、管道只能承载无格式字节流以及缓冲区大小受限等缺点。

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

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

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

套接字:套解字socket也是一种进程间通信机制,与其他通信机制不同的是,它可用于不同主机间的进程通信。

1.1.5进程的空间模型⭐⭐⭐

Linux下给每一个进程分配虚拟内存空间,32位操作系统下,每个进程有4G虚拟内存空间。其中包括:

(1)内核区:用户代码不可见的区域,页表就存放在这个区域中。

(2)用户区:

代码段:只可读,不可写,程序代码段。

数据段:保存全局变量,静态变量的区域。

堆区:就是动态内存,通过malloc,new申请内存,有一个堆指针,可以通过brk系统调用调整堆指针。

文件映射区域:通过mmap系统调用,如动态库,共享内存等映射物理空间的内存区域。可以单独释放,不会产生内存碎片。

栈区:用于维护函数调用的上下文空间,用ulimit -s 查看。一般默认为8M

1.1.6一个进程可以创建多少线程,和什么有关⭐⭐

一个进程可用虚拟空间为2G,线程的栈大小为1MB,理论上最多能创建2048个线程。创建的数量主要由虚拟内存空间和线程的栈大小共同决定。

1.1.7进程线程的状态转换图 什么时候阻塞,什么时候就绪⭐⭐

1)进程有5种状态

创建状态 一个应用程序从系统启动,进入创建状态,需要获取系统资源创建管理块,完成资源分配。

就绪状态:进程已处于准备运行状态,即进程获得了除了处理器之外的一切所需资源,但还未获得处理器资源,无法运行。

运行状态(执行态) 获取处理器资源,进程在处理器上上运行(单核CPU下任意时刻只有一个进程处于运行状态)。

阻塞状态(暂停态) 又称为等待状态,进程正在等待某一事件而暂停运行如等待某资源为可用或等待 IO 操作完成。即使处理器空闲,该进程也不能运行。

终止状态(僵尸态) 进程正在从系统中消失。可能是进程正常结束或其他原因中断退出运行

从父进程调用fork()创建子进程开始,此时子进程处于创建态,系统为进程分配地址和资源后将进程加入就绪队列,进入就绪态。就绪态的进程得到CPU时间片调度正式运行,进入执行态。执行态有四种常见结果:

① 当时间片耗光或者被其他进程抢占,则重新进入就绪态,等待下一次CPU时间片;

② 由于某些资源暂时不可得到而进入“阻塞态”(欲读取的文件为空或欲获得的某个锁还处于不可获得状态),等待资源可得后再唤醒,唤醒后进入就绪态

收到SIGSTOP/SIGTSTP停止信号进入阻塞态,直到收到SIGCONT继续运行信号重新进入就绪态;

④ 进程执行结束,通过内核调用do_exit()进入终止态,等待系统回收资源。当父进程调用wait()/waitpid()后接收结束子进程。

2)线程有6种状态

初始(NEW)新创建了一个线程对象,但还没有调用start()方法。

运行(RUNNABLE)线程对象创建后,其他线程(比如main线程)调用了该对象的start()方法。该状态的线程位于可运行线程池中,等待被线程调度选中,获取CPU的使用权,此时处于就绪状态(ready)。就绪状态的线程在获得CPU时间片后变为运行中状态(running)。

阻塞(BLOCKED)表示线程阻塞于锁。注意和进程的区别,进程是IO阻塞

等待(WAITING)进入该状态的线程需要等待其他线程做出一些特定动作(通知或中断)。

超时等待(TIMED_WAITING)该状态不同于WAITING,它可以在指定的时间后自行返回。

终止(TERMINATED)表示该线程已经执行完毕。

1.1.8父进程、子进程的关系⭐⭐⭐⭐⭐

父进程调用fork()以后,克隆出一个子进程,子进程和父进程拥有相同内容的代码段、数据段和用户堆栈区,但子进程其实只复制父进程的进程控制块(PCB)大部分信息,而代码段,数据段和用户堆栈内存空间是与子进程共享的

子进程从父进程继承的主要有:用户号和用户组号;堆栈;共享内存;当前工作目录;打开文件的描述符等;但父进程和子进程拥有独立的地址空间和ID参数、不同的父进程号和自己的文件描述符

1)子进程继承父进程:
用户号和用户组号 环境 堆栈 共享内存 打开文件的描述符 执行时关闭(Close-on-exec)标志 信号(Signal)控制设定 进程组号 当前工作目录 根目录文件方式创建屏蔽字资源限制控制终端

2)子进程独有的(区别):

进程号ID 不同的父进程号ID 自己的文件描述符和目录流的拷贝 子进程不继承父进程的进程正文(text),数据和其他锁定内存(memory locks 不继承异步输入和输出

1.1.9什么是进程上下文、中断上下文⭐⭐

进程空间分为内核空间和用户空间,在内核空间执行的通常是驱动程序,中断相关程序,内核调度程序,内存管理及其操作程序。而我们编写的应用程序运行在用户空间。其中内核运行在最高权限级别的内核态,这个级别有最高权限可以进行所有操作,而应用程序运行在较低级别的用户态,内核态和用户态有自己的内存映射,即自己的地址空间

当我们创建一个进程(例如main函数)控制一个外设时(比如控制一个LED灯亮),我们编写的在用户空间的代码将通过系统调用(操作系统提供给用户空间的接口函数)进入内核空间,由内核继续代表这个进程运行于内核空间,这时候就涉及上下文的切换。用户空间和内核空间具有不同的地址映射,通用或专用的寄存器组,而用户空间的进程要传递很多变量、参数给内核,内核也要保存用户进程的一些寄存器、变量等,以便系统调用结束后回到用户空间继续执行。

1)进程上文:其实指进程由用户态切换到内核态时,需要保存用户态时cpu寄存器中的值,进程状态以及堆栈上的内容。

进程下文:其是指切换到内核态后执行的程序,即进程运行在内核空间的部分。

同理,当由硬件通过触发信号,导致内核调用中断处理程序,进入内核空间。这个过程中,硬件的一些变量和参数也要传递给内核,内核通过这些参数进行中断处理:

2)中断上文:可以看作就是硬件传递过来的这些参数和内核需要保存的一些其他环境(主要是当前被中断的进程环境。

中断下文:执行在内核空间的中断服务程序。

3)那么运行在中断上下文的代码时,有什么不能做的事?

睡眠或者放弃CPU。这样做的后果是灾难性的,因为内核在进入中断之前会关闭进程调度,一旦睡眠或者放弃CPU,这时内核无法调度别的进程来执行,系统就会死掉

尝试获得信号量。如果获得信号量,可能会导致睡眠,会产生和上面相同的情况

执行耗时的任务。中断处理应该尽可能快,因为内核要响应大量服务和请求,中断上下文占用CPU时间太长会严重影响系统功能。

访问用户空间的虚拟地址。因为中断上下文是和特定进程无关的,它是内核代表硬件运行在内核空间,所以在中断上下文无法访问用户空间的虚拟地址。

1.2 并发(同步,互斥),异步,阻塞,非阻塞的理解

1.2.1并发,同步,互斥,异步,阻塞,非阻塞的理解⭐⭐⭐⭐⭐

并发:在操作系统中,是指一个时间段中有几个程序都处于已启动运行到运行完毕之间,且这几个程序都是在同一个处理机上运行。其中两种并发关系分别是同步和互斥

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的

同步:是指在互斥的基础上(大多数情况),通过其它机制实现访问者对资源的有序访问,协同完成某件事。指一个进程在执行某个请求的时候,若该请求需要一段时间才能返回信息,那么这个进程将会一直等待下去,直到收到返回信息才继续执行下去;同步是一种更为复杂的互斥,而互斥是一种特殊的同步。

异步:进程不需要一直等下去,而是继续执行下面的操作,不管其他进程的状态。当有消息返回时系统会通知进程进行处理,这样可以提高执行的效率。

阻塞与非阻塞:阻塞与非阻塞是当进程在访问数据时,根据IO操作的就绪状态不同而采取的不同处理方式。比如主程序调用一个函数要读取一个文件的内容,阻塞方式下:主程序会等到函数读取完再继续往下执行非阻塞方式:读取函数会立刻返回一个状态值给主程序,主程序不等待文件读取完就继续往下执行。一般来说可以分为同步阻塞(常用)、同步非阻塞、异步阻塞与异步非阻塞(常用)。

1.2.2什么是线程同步和互斥⭐⭐⭐⭐⭐

与进程的同步和互斥基本一致

线程同步:指线程之间的一种制约关系(多个线程相互协作时,存在的依赖关系),一个线程的执行依赖另一个线程的消息,当它没有得到另一个线程的消息时应等待,直至消息到达时才被唤醒。

线程互斥:指对于共享的进程系统资源,各个线程访问时具有排它性。当若干个线程都要使用某一共享资源时,任何时刻最多只允许一个线程使用,其它线程必须等待,直到占用资源者释放该资源。线程互斥是一种特殊的线程同步

1.2.3线程同步与阻塞的关系?同步一定阻塞吗?阻塞一定同步吗?⭐⭐⭐

阻塞,非阻塞是使用同步机制的结果之一。同步是个过程,阻塞是进程的一个状态。当多个线程访问同一个资源时,规定同一时间只有一个线程可以进行访问,所以后访问的线程将阻塞,等待前访问的线程访问完成。

  注意:线程同步不一定发生阻塞!线程同步的时候,需要协调推进速度,只有当访问同一资源出现互相等待和互相唤醒才会发生阻塞。

1.3 孤儿进程、僵尸进程、守护进程的概念

1.3.1 基本概念 ⭐⭐

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

僵尸进程:一个进程使用fork()创建子进程,如果子进程退出,而父进程没有通过调用wait()(或其变体 waitpid()、waitid()等)函数回收子进程资源/状态信息并归还给系统,那么此时子进程的进程描述符仍然保存在系统中,这种子进程则称为僵尸进程;

守护进程:运行在后台、不与任何终端关联(不受终端控制)的一种特殊进程,它独立于控制终端并且周期性地执行某种任务或等待处理某些事情的发生。通常在系统启动时就在运行,以root用户或特殊用户运行(apache和postfix),能处理一些系统级的任务。

1.3.2 如何创建守护进程:⭐⭐

① 调用fork(),创建新的子进程,并调用exit()终止父进程,(创建孤儿进程)同时保证子进程不是进程组长(子进程虽然继承父进程的进程组ID,但有独立的进程ID)。

② 子进程调用setsid()创建新的会话区

将当前目录改为根目录(当前目录不能被卸载,它是作为守护进程的工作目录

重设文件权限掩码umask。(把文件权限掩码设置为 0,确保子进程有最大操作权限、增强守护进程的灵活性)

关闭不再需要的文件描述符。(使得守护进程不再持有从其父进程继承过来的任何文件描述符,防止消耗系统资源)

将标准输入、标准输出、标准错误重定向到 /dev/null。(使得守护进程的输出无处显示、

也无处从交互式用户那里接收输入。)

1.3.3 正确处理孤儿进程、僵尸进程的方法⭐⭐⭐⭐⭐

1)僵尸进程的处理方法:

通过信号机制解决:子进程退出时向父进程发送SIGCHILD信号,父进程处理SIGCHILD信号。在信号处理函数中调用wait()处理僵尸进程

fork两次:可以避免子进程成为僵尸进程,父进程人为fork一个子进程,然后继续工作,子进程fork一个孙进程后退出,那么孙进程被init进程接管,孙进程结束后,init会回收。不过子进程的回收 还要自己做。两次fork的原理是将孙进程成为孤儿进程,从而被转交给Init进程托管,孤儿进程的“父进程”变为init进程,当孙进程退出的时候,init就会回收孙进程的资源,通过init进程可以处理僵尸进程。

kill -9 杀死僵尸进程的父进程。若父进程是1号进程init进程,则挂起僵尸进程。

2)孤儿进程的处理方法:

收养:任何孤儿进程产生时都会立即被系统进程(init)自动接收为子进程(init会周期性的调用wait函数)。

注:在此需注意,虽然事实上该进程已有init作为其父进程,但由于创建该进程的进程已不存在,所以仍应称之为“孤儿进程”

进程组:引入进程组,在父进程终止后,用户的Shell会将父进程所在的进程组标为孤儿进程组,并向所有子进程发出SIGHUP信号,以试图结束其运行

远程调用客户端发起请求后突然崩溃,服务器端进程会成为孤儿进程。此时可以:1)终止机制:强制杀死孤儿进程2)再生机制:服务器在指定时间内查找调用的客户端,若找不到则直接杀死孤儿进程;3)超时机制:给每个进程指定一个确定的运行时间,若超时仍未完成则强制终止之。若有需要,亦可让进程在指定时间耗尽之前申请延时。

补充:

1、防止线程之间相互竞争资源的方法。

同步机制:指的是在一定的时间内只允许某一个线程访问某个资源,在互斥的基础上,通过其它机制实现访问者对资源的有序访问。具体可以使用一下四种方式实现:

1)互斥锁:同时运行的多个线程任务可能都需要使用同一进程资源,一个线程在使用共享内存时,会把门锁住,来控制对共享资源的访问,等空间被释放,才能再进去用这个空间。互斥锁只有两种状态,即上锁( lock )和解锁( unlock ) 。同时互斥锁的作用域仅仅在于线程

互斥锁特点:

原子性:这意味着操作系统(或pthread函数库)保证了如果一个线程锁定了一个互斥量,没有其他线程可以在同一时间可以成功锁定这个互斥量;

唯一性:一个线程锁定一个互斥量,在它解除锁定之前,其他线程无法锁定这个互斥量;

非繁忙等待:一个线程锁定一个互斥量,第二个线程试图去锁定这个互斥量时,则第二个线程将被挂起(不占用任何cpu资源),直到第一个线程解除对这个互斥量的锁定为止,第二个线程则被唤醒并继续执行,同时锁定这个互斥量。

2)条件变量:线程在等待某些满足条件时使线程进入睡眠状态,即阻塞一个线程,一旦条件满足就唤醒,这样不会占用宝贵的互斥锁,不需要频繁查询锁的状态,实现高效。

3)自旋锁:当一个线程要访问某个共享资源的时候首先要先获取相应的锁,锁只能被一个线程持有,只要此线程不释放持有的锁,那么其他的线程就不能获取此锁,处于忙循环-旋转-等待状态。

缺点:等待自旋锁的线程会一直处于自旋状态,这样会浪费处理器时间,降低系统性能。所以自旋锁适用于短时期的轻量级加锁。

4)读写(自旋)锁 适用于对数据结构的读操作次数多于写操作次数的场合。(理解为一个共享信息表可以并发读取,但是不可以修改时读取)

读写锁处于写锁定的状态:则在解锁之前,所有试图加锁的线程都会阻塞;

读写锁处于读锁定的状态:则所有试图以读模式加锁的线程都可得到访问权,但是以写模式加锁的线程则会阻塞;

读写锁处于读模式的锁(未加锁)状态时:有另外的线程试图以写模式加锁,则读写锁会阻塞读模式加锁的请求,这样避免了读模式锁长期占用,导致的写模式锁长期阻塞的情况;

5)信号量:信号量常常用于控制对共享资源的访问数(信号量值)。例如:一个房子有 10 把钥匙,这 10 把钥匙就相当于信号量值为10。信号量可以使等待资源线程进入休眠状态(而不是一直自旋),因此信号量不能用于中断,中断不能休眠。同时适用于那些占用资源比较久的场合。

缺点:信号量的开销要比自旋锁大,因为信号量使线程进入休眠状态以后会切换线程,切换线程就会有开销。

注:信号量中存在一个进程等待队列,未获取锁的进程将挂到该队列中,然后主动调用schedule()切换进程,让出cpu。

6)互斥体:信号量值设置为1即为互斥体(mutex)。互斥访问表示一次只有一个线程可以访问共享资源,不能递归申请互斥体。

注意:1、mutex 可以导致休眠,因此不能在中断中使用 mutex,同时不能递归上锁和解锁。

2、管道和命名管道的区别

1)管道:把一个进程连接到另一个进程的数据流称为管道,实现数据以数据流的方式在进程间流动。其特点:

① 管道是半双工的,数据只能向一个方向流动;需要双方通信时,需要建立起两个管道;

② 只能用于父子进程或者兄弟进程之间(具有亲缘关系的进程);

单独构成一种独立的文件系统:管道对于管道两端的进程而言,就是一个文件,但它不是普通的文件,它不属于某种文件系统,而是自立门户,单独构成一种文件系统,并且只存在于内存中。

④数据的读出和写入:一个进程向管道中写的内容被管道另一端的进程读出。写入的内容每次都添加在管道缓冲区的末尾,并且每次都是从缓冲区的头部读出数据

2)命名管道:命名管道(named pipe)也称为FIFO(遵循先进先出),它是一种文件类型,创建一个FIFO文件类似于创建一个普通文件。FIFO解决了只有具有亲缘关系的进程间才能通信的问题,它提供一个路径名与之关联,以FIFO的文件形式存放于文件系统中。只要可以访问该路径,就能够彼此通过FIFO相互通信,因此,通过FIFO不相关的进程也能交换数据命名管道区别于管道主要是以下两点:

命名管道可以用于任何两个进程间的通信,而并不限制这两个进程同源,因此命名管道的使用比管道的使用要方便灵活。

② 命名管道作为一种特殊的文件存放于文件系统中,而不是像管道一样存放于内存(管道使用完毕后消失)。当进程对命名管道的使用结束后,命名管道依然存在于文件系统中,除非对其进行删除操作,否则该命名管道不会消失

3I/O多路复用

       I/O 多路复用(IO multiplexing)本质是通过一种机制,让单个进程可以监视多个文件描述符,一旦发现某个文件描述符(也就是某个文件)可以执行 I/O 操作时,能够知应用程序进行相应的读写操作

selectpollepoll 都是 I/O多路复用的机制。

select,poll,epoll 都是同步 IO。所谓同步 IO,是读写是阻塞的,需要在读写事件就绪后进行读写操作

Select/poll调用 select/poll会一直阻塞,直到某一个或多个文件描述符成为就绪态(可以读或写),用于查询文件描述符上是否可以执行 I/O 操作。管理多个描述符也是进行轮询,会无差异轮询所有流,找出能读/写数据的流进行操作。poll无最大文件描述符数量的限制。

epoll epoll模型修改主动轮询为被动通知,当有事件发生时,被动接收通知。所以epoll模型注册套接字后,主程序可做其他事情,当事件发生时,接收到通知后再去处理。所以epoll是事件驱动

异步 IO (信号驱动IO):IO多路复用的机制,进程会先执行任何其它的任务,直到文件描述符可以执行 I/O 操作时,内核会发送一个信号给进程,执行预先注册好的信号处理函数。

4Fork函数

1)内部实现原理

fork()系统调用通过复制一个现有进程来创建一个全新的进程。进程被存放在一个叫做任务队列的双向循环链表当中,链表当中的每一项都是类型为task_struct称为进程描述符的结构。当进程调用fork后,当控制转移到内核中的fork代码后,内核会做4件事情:

1、分配新的内存块和内核数据结构给子进程

2、将父进程部分数据结构内容拷贝至子进程

3、添加子进程到系统进程列表当中

4fork返回,开始调度器调度

2fork函数为什么是一次调用,却返回了两次呢?

答:由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。可能有三种不同的返回值:

在父进程中,fork返回新创建子进程的进程ID

在子进程中,fork返回0

如果出现错误,fork返回一个负值。

3)进程创建函数forkvfork的区别?

fork()①父子进程的执行次序不确定。②子进程拷贝父进程的地址空间,子进程是父进程的一个复制品。

vfork()保证子进程先运行,在它调用 exec(进程替换) exit(退出进程)之后父进程才可能被调度运行。②子进程共享父进程的地址空间(准确来说,在调用 exec(进程替换) exit(退出进程) 之前与父进程数据是共享的)。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值