面试宝典3

1、请你说说fork、wait、exec函数

fork
       创建一个子进程进程,两个进程都读同一块内存。这个函数有两个返回值,子进程返回0,父进程返回子进程id,出错返回-1。可以用getpid()函数得到各自进程的pid。

wait
       wait()函数用于父进程,它阻塞直到一个子进程结束或者该进程接收到了一个指定的信号为止。如果该父进程没有子进程或者它的子进程已经结束,则wait()函数就会立即返回。

exec
       exec族函数可以让子进程执行与父进程不同的程序,即让子进程执行另一个程序。

fork和vfork的区别:
       fork 创建一个进程时,子进程只是完全复制父进程的资源,这样得到的 子进程独立于父进程,具有良好的并发性,但是二者之间的通讯需要通过专门的 通讯机制。通过 fork 创建的子进程系统开销很大,需 要将每种资源(数据空间,堆和栈)都复制一个副本。这些系统开销并不是所有的 情况下都是必须的。
       vfork 创建的子进程共享地址空间,也就是说子进程完全运行在父进程的地址空间上,子进程对虚拟地址空间任何数据的修改同样为父进程所见。但 vfork 创 建子进程后,父进程会被阻塞知道子进程调用 exec 或 exit。而 fork 的父子进程 运行顺序是不定的,通过 vfork 可以减少不必要的开销。

2、请你说一说Linux虚拟地址空间

       为了防止不同进程同一时刻在物理内存中运行而对物理内存的争夺和践踏,采用了虚拟内存。 虚拟内存技术使得不同进程在运行过程中,它所看到的是自己独自占有了当前系统的4G内存 。所有进程共享同一物理内存,每个进程只把自己目前需要的虚拟内存空间映射并存储到物 理内存上。 事实上,在每个进程创建加载时,内核只是为进程“创建”了虚拟内存的布局,具 体就是初始化进程控制表中内存相关的链表,实际上并不立即就把虚拟内存对应位置的程序 数据和代码(比如.text .data段)拷贝到物理内存中,只是建立好虚拟内存和磁盘文件之间的 映射就好(叫做存储器映射),等到运行到对应的程序时,才会通过缺页异常,来拷贝数据。 还有进程运行过程中,要动态分配内存,比如malloc时,也只是分配了虚拟内存,即为这块 虚拟内存对应的页表项做相应设置,当进程真正访问到此数据时,才引发缺页异常。

虚拟内存的好处:
       1.扩大地址空间
       2.内存保护:每个进程运行在各自的虚拟内存地址空间,互相不能干扰对方。虚存还对特定的内存地址提供写 保护,可以防止代码或数据被恶意篡改。
       3.公平内存分配。采用了虚存之后,每个进程都相当于有同样大小的虚存空间。
        4.当进程通信时,可采用虚存共享的方式实现。
       5.当不同的进程使用同样的代码时,比如库文件中的代码,物理内存中可以只存储一份这样的代码,不同的进 程只需要把自己的虚拟内存映射过去就可以了,节省内存
       6.虚拟内存很适合在多道程序设计系统中使用,许多程序的片段同时保存在内存中。当一个程序等待它的一部 分读入内存时,可以把CPU交给另一个进程使用。在内存中可以保留多个进程,系统并发度提高
       7.在程序需要分配连续的内存空间的时候,只需要在虚拟内存空间分配连续空间,而不需要实际物理内存的连续空间,可以利用碎片

虚拟内存的代价:
       1.虚存的管理需要建立很多数据结构,这些数据结构要占用额外的内存
       2.虚拟地址到物理地址的转换,增加了指令的执行时间。
       3.页面的换入换出需要磁盘I/O,这是很耗时的
       4.如果一页中只有一部分数据,会浪费内存。

3、说一说操作系统中程序的内存结构

在这里插入图片描述
       一个程序在内存上由BSS段、data段、text段三个组成的。在没有调入内存前,可执行程序分为代码段、数据区和未初始化数据区三部分。

BSS段:(bss segment)
       通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。bss段(未进行初始化的数据)的内容并不存放在磁盘上的程序文件中。其原因是内核在程序开始运行前将它们设置为0。需要存放在程序文件中的只有正文段和初始化数据段。text段和data段在编译时已经分配了空间,而BSS段并不占用可执行文件的大小,它是由链接器来获取内存的。

数据段:(data segment)
       通常是指用来存放程序中已初始化的全局变量的一块内存区域。数据段属于静态内存分配。

代码段:(code segment/text segment)
       通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。

堆(heap):
       堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。
       这里区别 堆区:用于动态分配内存,位于BSS和栈中间的地址区域。由程序员申请分配和释放。堆是从低地址位向高地址位增长,采用链式存储结构。频繁的malloc/free造成内存空间的不连续,产生碎片。当申请堆空间时库函数是按照一定的算法搜索可用的足够大的空间。因此堆的效率比栈要低的多。

栈(stack):
       栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括弧“{}”中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变量)。除此以外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值也会被存放回栈中。由于栈的先进先出特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
       这里区别 栈区:由编译器自动释放,存放函数的参数值、局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存放到栈中。然后这个被调用的函数再为他的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用。栈区是从高地址位向低地址位增长的,是一块连续的内存区域,最大容量是由系统预先定义好的,申请的栈空间超过这个界限时会提示溢出,用户能从栈中获取的空间较小。

4、说一说操作系统中的缺页中断

       malloc()和mmap()等内存分配函数,在分配时只是建立了进程虚拟地址空间, 并没有分配虚拟内存对应的物理内存。当进程访问这些没有建立映射关系的 虚拟内存时,处理器自动触发一个缺页异常。
       缺页中断:在请求分页系统中,可以通过查询页表中的状态位来确定所要访 问的页面是否存在于内存中。每当所要访问的页面不在内存是,会产生一次 缺页中断,此时操作系统会根据页表中的外存地址在外存中找到所缺的一页 ,将其调入内存。

缺页本身是一种中断,与一般的中断一样,需要经过4个处理步骤:
       1、保护CPU现场
       2、分析中断原因
       3、转入缺页中断处理程序进行处理
       4、恢复CPU现场,继续执行

但是缺页中断是由于所要访问的页面不存在于内存时,由硬件所产生的一种特殊的中断,因此,与一般的中断存在区别:
       1、在指令执行期间产生和处理缺页中断信号
       2、一条指令在执行期间,可能产生多次缺页中断
       3、缺页中断返回是,执行产生中断的一条指令,而一般的中断返回是,执行下一条指令。

5、说一说并发(concurrency)和并行(parallelism)

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

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

6、说一说操作系统中的页表寻址

       页式内存管理,内存分成固定长度的一个个页片。操作系统为每一个进程维护了一个从虚拟地址到物理地址的映射关系的数据结构,叫页表,页表的内容就是该进程的虚拟地址到物理地址的一个映射。页表中的每一项都记录了这个页的基地址。通过页表,由逻辑地址的高位部分先找到逻辑地址对应的页基地址,再由页基地址偏移一定长度就得到最后的物理地址,偏移的长度由逻辑地址的低位部分决定。一般情况下,这个过程都可以由硬件完成,所以效率还是比较高的。页式内存管理的优点就是比较灵活,内存管理以较小的页为单位,方便内存换入换出和扩充地址空间。

7、什么是死锁,简述死锁发生的四个必要条件,如何避免与预防死锁

什么是死锁
       死锁是指多个进程因竞争资源而造成的一种僵局(互相等待),若无外力作用,这些进程都将无法向前推进。例如,在某一个计算机系统中只有一台打印机和一台输入 设备,进程P1正占用输入设备,同时又提出使用打印机的请求,但此时打印机正被进程P2 所占用,而P2在未释放打印机之前,又提出请求使用正被P1占用着的输入设备。这样两个进程相互无休止地等待下去,均无法继续执行,此时两个进程陷入死锁状态。

死锁产生的原因
       1、系统资源的竞争导致系统资源不足,以及资源分配不当,导致死锁。
2、进程在运行过程中,请求和释放资源的顺序不当,会导致死锁。

产生死锁的四个必要条件:
       1、互斥条件:一个资源每次只能被一个进程使用,即在一段时间内某 资源仅为一个进程所占有。此时若有其他进程请求该资源,则请求进程只能等待。
       2、请求与保持条件:进程已经保持了至少一个资源,但又提出了新的资源请求,而该资源 已被其他进程占有,此时请求进程被阻塞,但对自己已获得的资源保持不放。
       3、不可剥夺条件:进程所获得的资源在未使用完毕之前,不能被其他进程强行夺走,即只能 由获得该资源的进程自己来释放(只能是主动释放)。
       4、循环等待条件: 若干进程间形成首尾相接循环等待资源的关系
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。

死锁的避免与预防:
       1、系统对进程发出每一个系统能够满足的资源申请进行动态检查,并根据检查结果决定是否分配资源,如果分配后系统可能发生死锁,则不予分配,否则予以分配。这是一种保证系统不进入死锁状态的动态策略。
       2、理解了死锁的原因,尤其是产生死锁的四个必要条件,就可以最大可能地避免、预防和解除死锁。所以,在系统设计、进程调度等方面注意如何让这四个必要条件不成立,如何确定资源的合理分配算法,避免进程永久占据系统资源。此外,也要防止进程在处于等待状态的情况下占用资源。因此,对资源的分配要给予合理的规划。
       3、死锁预防是设法至少破坏产生死锁的四个必要条件之一,严格的防止死锁的出现,而死锁避免则不那么严格的限制产生死锁的必要条件的存在,因为即使死锁的必要条件存在,也不一定发生死锁。死锁避免是在系统运行过程中注意避免死锁的最终发生。

8、请问虚拟内存和物理内存怎么对应

       进程得到的这4G虚拟内存是一个连续的地址空间(这也只是进程认为),而实际上,它通常是被分隔成多个物理内存碎片,还有一部分存储在外部磁盘存储器上,在需要时进行数据交换。

9、说一说操作系统中的字节对齐

       字节对齐:即以结构体成员中占内存最多的数据类型所占的字节数为标准,所有的成员在分配内存时都要与这个长度对齐。

10、什么是大端小端以及如何判断大端小端

       大端是指低字节存储在高地址;
       小端是指低字节存储在低地址。
       我们可以根据联合体来判断该系统是大端还是小端。因为联合体变量总是从低地址存储。

11、回答一下静态变量什么时候初始化

       静态变量存储在虚拟地址空间的数据段和bss段,C语言中其在代码执行之前初始化,属于编译期初始化。而C++中由于引入对象,对象生成必须调用构造函数,因此C++规定全局或局部静态对象当且仅当对象首次用到时进行构造。

12、说一说TCP的三次握手和四次挥手的过程及原因

在这里插入图片描述
TCP的三次握手过程如下:
       C-> SYN -> S
       S->SYN/ACK->C
       C->ACK->S

       第一次握手:建立连接时,客户端发送syn包(syn=x)到服务器,并进入SYN_SENT状态,等待服务器确认;SYN:同步序列编号(Synchronize Sequence Numbers)。
       第二次握手:服务器收到syn包,必须确认客户的SYN(ack=x+1),同时自己也发送一个SYN包(syn=y),即SYN+ACK包,此时服务器进入SYN_RECV状态;
       第三次握手:客户端收到服务器的SYN+ACK包,向服务器发送确认包ACK(ack=y+1),此包发送完毕,客户端和服务器进入ESTABLISHED(TCP连接成功)状态,完成三次握手。

三次握手的原因:
       三次握手可以防止已经失效的连接请求报文突然又传输到服务器端导致的服务器资源浪费。例如,客户端先发送了一个SYN,但是由于网络阻塞,该SYN数据包在某个节点长期滞留。然后客户端又重传SYN数据包并正确建立TCP连接,然后传输完数据后关闭该连接。该连接释放后失效的SYN数据包才到达服务器端。在二次握手的前提下,服务器端会认为这是客户端发起的又一次请求,然后发送SYN ,并且在服务器端创建socket套接字,一直等待客户端发送数据。但是由于客户端并没有发起新的请求,所以会丢弃服务端的SYN 。此时服务器会一直等待客户端发送数据从而造成资源浪费。

在这里插入图片描述
TCP的四次挥手过程如下:
       C->FIN->S
       S->ACK->C
       S->FIN->C
       C->ACK->S

       第一次挥手:客户端进程发出连接释放报文,并且停止发送数据。释放数据报文首部,FIN=1,其序列号为seq=u(等于前面已经传送过来的数据的最后一个字节的序号加1),此时,客户端进入FIN-WAIT-1(终止等待1)状态。 TCP规定,FIN报文段即使不携带数据,也要消耗一个序号。
       第二次挥手:服务器收到连接释放报文,发出确认报文,ACK=1,ack=u+1,并且带上自己的序列号seq=v,此时,服务端就进入了CLOSE-WAIT(关闭等待)状态。TCP服务器通知高层的应用进程,客户端向服务器的方向就释放了,这时候处于半关闭状态,即客户端已经没有数据要发送了,但是服务器若发送数据,客户端依然要接受。这个状态还要持续一段时间,也就是整个CLOSE-WAIT状态持续的时间。客户端收到服务器的确认请求后,此时,客户端就进入FIN-WAIT-2(终止等待2)状态,等待服务器发送连接释放报文(在这之前还需要接受服务器发送的最后的数据)。
       第三次挥手:服务器将最后的数据发送完毕后,就向客户端发送连接释放报文,FIN=1,ack=u+1,由于在半关闭状态,服务器很可能又发送了一些数据,假定此时的序列号为seq=w,此时,服务器就进入了LAST-ACK(最后确认)状态,等待客户端的确认。
       第四次挥手:客户端收到服务器的连接释放报文后,必须发出确认,ACK=1,ack=w+1,而自己的序列号是seq=u+1,此时,客户端就进入了TIME-WAIT(时间等待)状态。注意此时TCP连接还没有释放,必须经过2∗∗MSL(最长报文段寿命)的时间后,当客户端撤销相应的TCB后,才进入CLOSED状态。服务器只要收到了客户端发出的确认,立即进入CLOSED状态。同样,撤销TCB后,就结束了这次的TCP连接。可以看到,服务器结束TCP连接的时间要比客户端早一些。

四次挥手的原因:
       由于连接的关闭控制权在应用层,所以被动关闭的一方在接收到FIN包时,TCP协议栈会直接发送一个ACK确认包,优先关闭一端的通信。然后通知应用层,由应用层决定什么时候发送FIN包。应用层可以使用系统调用函数read==0来判断对端是否关闭连接。

13、请问TCP握手为什么两次不可以,为什么不用四次

       3次握手完成两个重要的功能,既要双方做好发送数据的准备工作(双方都知道彼此已准备好),也要允许双方就初始序列号进行协商,这个序列号在握手过程中被发送和确认。
现在把三次握手改成仅需要两次握手,死锁是可能发生的。

  • 第一次握手: A给B打电话说,你可以听到我说话吗?
  • 第二次握手: B收到了A的信息,然后对A说: 我可以听得到你说话啊,你能听得到我说话吗?
  • 第三次握手: A收到了B的信息,然后说可以的,我要给你发信息啦!
    在三次握手之后,A和B都能确定这么一件事: 我说的话,你能听到; 你说的话,我也能听到。 这样,就可以开始正常通信了。

       如果两次,那么B无法确定B的信息A是否能收到,所以如果B先说话,可能后面的A都收不到,会出现问题 。
       如果四次,那么就造成了浪费,因为在三次结束之后,就已经可以保证A可以给B发信息,A可以收到B的信息; B可以给A发信息,B可以收到A的信息。

14、说一下TCP拥塞控制

       发送方维持一个叫做拥塞窗口cwnd(congestion window)的状态变量。拥塞窗口的大小取决 于网络的拥塞程度,并且动态地在变化。发送方让自己的发送窗口等于拥塞窗口,另外考虑到 接受方的接收能力,发送窗口可能小于拥塞窗口。慢开始算法的思路就是,不要一开始就发送 大量的数据,先探测一下网络的拥塞程度,也就是说由小到大逐渐增加拥塞窗口的大小。
       过程cwnd的大小呈指数增长,直到超过慢启动门限,然后进入拥塞避免阶段,cwnd的大小线性 增长,当出现网络拥塞(三个重复的ack或者超时)时候,将慢启动门限设置为出现拥塞时候大小 的一半,cwnd的大小重新从0开始进入慢启动阶段。
       快重传和快恢复:快重传要求接收方在收到一个失序的报文段后就立即发出重复确认(为的是使 发送方及早知道有报文段没有到达对方)而不要等到自己发送数据时捎带确认。快重传算法规定 ,发送方只要一连收到三个重复确认就应当立即重传对方尚未收到的报文段,而不必继续等待设 置的重传计时器时间到期

15、说一下socket编程中服务端和客户端主要用到哪些函数

服务器端程序:
       1、创建一个socket,用函数socket()
       2、绑定IP地址、端口等信息到socket上,用函数bind()
       3、设置允许的最大连接数,用函数listen()
       4、接收客户端上来的连接,用函数accept()
       5、收发数据,用函数send()和recv(),或者read()和write()
       6、关闭网络连接closesocket()

客户端程序:
       1、创建一个socket,用函数socket()
       2、设置要连接的对方的IP地址和端口等属性,用函数bind()
       3、连接服务器,用函数connect()
       4、收发数据,用函数send()和recv(),或read()和write()
       5、关闭网络连接closesocket()

16、说一下进程与线程的概念

       进程(process)和线程(thread)是操作系统的基本概念,但是它们比较抽象,不容易理解。下面这篇材料,是一个很好的类比,可以把它们解释地清晰易懂。
       计算机的核心是CPU,它承担了所有的计算任务。它就像一座工厂,时刻在运行。假定工厂的电力有限,一次只能供给一个车间使用。也就是说,一个车间开工的时候,其他车间都必须停工。背后的含义就是,单个CPU一次只能运行一个任务。进程就好比工厂的车间,它代表CPU所能处理的单个任务。任一时刻,CPU总是运行一个进程,其他进程处于非运行状态。
       一个车间里,可以有很多工人。他们协同完成一个任务。线程就好比车间里的工人。一个进程可以包括多个线程。车间的空间是工人们共享的,比如许多房间是每个工人都可以进出的。这象征一个进程的内存空间是共享的,每个线程都可以使用这些共享内存。
       可是,每间房间的大小不同,有些房间最多只能容纳一个人,比如厕所。里面有人的时候,其他人就不能进去了。这代表一个线程使用某些共享内存时,其他线程必须等它结束,才能使用这一块内存。一个防止他人进入的简单方法,就是门口加一把锁。先到的人锁上门,后到的人看到上锁,就在门口排队,等锁打开再进去。这就叫"互斥锁"(Mutual exclusion,缩写 Mutex),防止多个线程同时读写某一块内存区域。
       还有些房间,可以同时容纳n个人,比如厨房。也就是说,如果人数大于n,多出来的人只能在外面等着。这好比某些内存区域,只能供给固定数目的线程使用。这时的解决方法,就是在门口挂n把钥匙。进去的人就取一把钥匙,出来时再把钥匙挂回原处。后到的人发现钥匙架空了,就知道必须在门口排队等着了。这种做法叫做"信号量"(Semaphore),用来保证多个线程不会互相冲突。

       进程是计算机中的程序关于某数据集合上的一次运行活动,是系统进行 资源分配和调度的基本单位,是操作系统结构的基础。它是系统资源管理的最小 单位。
       线程,有时称为轻量级进程,是程序执行流的最小单元。线程是进程中的 一个实体,是被系统独立调度和分配的基本单位,线程自己不拥有资源,只拥有 一点儿在运行中必不可少的资源,他可以与同属一个进程的其他线程共享进程所 拥有的全部资源。

17、说一说有了进程、为什么还要有线程

       进程有很多优点,它提供了多道编程,让我们感觉我们每个人都用有自 己的 CPU 和其他资源,可以提高自己的利用率。但是进程只能在一个时间干一 件事,在执行过程中如果阻塞,整个程序就会挂起。线程提高了进程的并发度, 还可以有效的利用多处理器和多核计算机

18、说一说线程间的同步方式,最好说出具体的系统调用

信号量
       信号量是一种特殊的变量,可用于线程同步。它只取自然数值,并且只支持两种操作:
       P(SV):如果信号量SV大于0,将它减一;如果SV值为0,则挂起该线程。
       V(SV):如果有其他进程因为等待SV而挂起,则唤醒,然后将SV+1;否则直接将SV+1。
其系统调用为:
       sem_wait(sem_t *sem):以原子操作的方式将信号量减1,如果信号量值为0,则sem_wait将被阻塞,直到这个信号量具有非0值。
       sem_post(sem_t *sem):以原子操作将信号量值+1。当信号量大于0时,其他正在调用sem_wait等待信号量的线程将被唤醒。

互斥量
       互斥量又称互斥锁,主要用于线程互斥,不能保证按序访问,可以和条件锁一起实现同步。当进入临界区 时,需要获得互斥锁并且加锁;当离开临界区时,需要对互斥锁解锁,以唤醒其他等待该互斥锁的线程。其主要的系统调用如下:
       pthread_mutex_init:初始化互斥锁
       pthread_mutex_destroy:销毁互斥锁
       pthread_mutex_lock:以原子操作的方式给一个互斥锁加锁,如果目标互斥锁已经被上锁,pthread_mutex_lock调用将阻塞,直到该互斥锁的占有者将其解锁。
       pthread_mutex_unlock:以一个原子操作的方式给一个互斥锁解锁。

条件变量
       条件变量,又称条件锁,用于在线程之间同步共享数据的值。条件变量提供一种线程间通信机制:当某个共享数据达到某个值时,唤醒等待这个共享数据的一个/多个线程。即,当某个共享变量等于某个值时,调用 signal/broadcast。此时操作共享变量时需要加锁。其主要的系统调用如下:
       pthread_cond_init:初始化条件变量
       pthread_cond_destroy:销毁条件变量
       pthread_cond_signal:唤醒一个等待目标条件变量的线程。哪个线程被唤醒取决于调度策略和优先级。
       pthread_cond_wait:等待目标条件变量。需要一个加锁的互斥锁确保操作的原子性。该函数中在进入wait状态前首先进行解锁,然后接收到信号后会再加锁,保证该线程对共享资源正确访问。

19、进程间通信的方法有哪些,各自有什么优缺点,哪一种最高效

       无名管道(亲源进程之间):管道是一种半双工的通信方式,数据只能单向 流动,而且只能在具有亲缘关系的进程间使用。进程的亲缘关系通常是指父子进 程关系。
       有名管道(任意进程之间):也是半双工通信方式,但是允许在没有亲缘关系的 进程之间使用,管道是先进先出的通信方式。
       共享内存(效率最高):共享内存就是映射一段能被其他进程所访问的内存,这 段共享内存由一个进程创建,但多个进程都可以访问。共享内存是最快的IPC方 式,他是针对其他进程间通信方式运行效率低而专门设计的。
       消息队列(具备同步的效果):消息队列是有消息的链表,存放在内核中并由消 息队列标识符标识。消息队列克服了信号传递消息少、管道只能承载无格式字节 流以及缓冲区大小受限等缺点。
       socket(不同主机之间的进程通信):用于不同机器间的进程通信。
       信号量(同步机制):是一个计数器,可以用来控制多个进程对共享资源的访问。 它常作为一种机制锁,防止某进程在防伪共享资源时,其他进程也访问该资源。 因此,主要作为进程间以及同一进程内不同线程之间的同步手段。
       内存映射

共享内存效率最高

20、进程和线程的区别

       (1)进程是系统进行资源分配的最基本单位,有独立的地址空间;线程是 CPU 调度的基本单位,没有单独的地址空间,有独立的栈、局部变量、寄存器等。
       (2)创建进程的开销大,包括创建虚拟地址空间等需要大量系统资源;线程开 销小,基本上只有一个内核对象和一个堆栈。
       (3)一个进程无法直接访问另一个进程的资源;同一进程内的多个线程共享进
程的资源。
       (4)进程切换开销大,线程切换开销小;进程间通信开销大,线程间通信开销 小。
       (5)线程属于进程,不能独立执行。每个进程至少要有一个线程,成为主线程。

21、什么是僵尸进程,有什么危害,以及处理僵尸进程的方法

       一个进程使用 fork()创建子进程,如果子进程退出,而父进程并没有调 用 wait 或者 waitpid 获取子进程的状态信息,那么子进程的进程描述符仍然保存 在系统中。我们称之为僵尸进程。
       危害:浪费系统资源,如果僵尸进程过多,那么就会有大量的进程号被僵尸 进程占用,但系统所能使用的进程是有限。将会因为没有可用的进程号而导致系 统不能产生新的进程。

处理方法:
       1.父进程等待及调用 wait 或 waitpid;
       2.杀死父进程,父进程死后 僵尸进程会变为孤儿进程,过继给 init 进程,init 始终会负责清理僵尸进程,由 它所产生的所有僵尸进程也跟着消失。

22、什么是孤儿进程

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

23、什么是后台进程

       Linux 后台进程也叫守护进程,是运行在后台的一种特殊进程。他独立 于控制终端并且周期性的执行某种任务或等待处理某些发生的事件。

24、线程之间通过什么交换数据

       全局变量;Message 消息机制;CEvent 对象

25、TCP和UDP的区别

       (1)TCP 面向连接(三次握手机制)、通信前需建立连接;UDP 面向无连接, 通信前不需要建立连接;
       (2)TCP 保障可靠传输(按序、无差错、不丢失、不重复);UDP 不保障可靠传 输,使用最大努力交付;
       (3)TCP 面向字节流的传输,UDP 面向数据报的传输。

26、TCP建立连接时的三次握手,断开连接时的四次挥手的具体过程

建立连接的三次握手------
       第一次握手是客户端 connect 连接到 server, serveracceptclient 的请求之后,向 client 端发送一个消息,相当于说我都准备好了,你连接上我了,这是第二次 握手,第三次握手就是 client 向 server 发送的,就是对第二次握手消息的确认, 之后 server 和 client 就开始通讯了。

断开连接的四次握手----
       断开连接的一端发送 close 请求是第一次握手,另外一端接收到断开连接的 请求之后需要对 close 进行确认,发送一个消息,这是第二次握手,发送了确认 消息之后还要向对端发送 close 消息,要关闭对对端的连接,这是第三次握手, 而在最初发送断开连接的一端接收到消息之后,进入到一个很重要的状态 time_wait 状态,最后一次握手是最初发送断开连接的一端接收到消息之后对消 息的确认。

27、TCP为什么不是两次握手而是三次握手

       如果 A 与 B 两个进程通信,如果仅是两次连接,可能出现的一种情况是: A 发送完请求报文以后,由于网络情况不好,出现了网络拥塞,即 B 延时很长时 间后收到报文,即此时 A 将此报文认定为失效的堆报文。B 收到报文后,会向 A 发起连接。此时两次握手完毕,B 会认为已经建立了连接可以通信,B 会一直等 到 A 发送的连接请求,而 A 对失效的报文回复自然不会处理。一次会陷入 B 忙 等的僵局,造成资源的浪费。

28、TCP和UDP的用途

       TCP 一般用于文件传输,发送或者接受邮件,远程登录等等;
       UDP 一般用于即时通信,在线视频,网络语音通话等等。

29、什么是线程池

       线程池是指在初始化一个多线程应用程序中创建一个线程集合,然后在 需要执行新的任务时,重用这些线程而不是新建一个线程。(为一个线程预分配 一个集合或者一个池来已被未来之需以及能够在一个应用程序中重用的技术,称 作线程池

30、线程池的作用以及为什么要用线程池

答:作用是限制系统中执行线程的数量。
       根据系统的环境情况,可以自动或手动设置线程数量,达到运行的最佳效果; 线程少了 浪费系统资源,多了造成系统资源拥挤,效率不高。用线程池控制线 程的数量,其他线程排队等候。一个任务执行完毕,再从队列中亲缘取最前面的 任务开始执行。若是队列里没有等待进程,线程池的这一资源处于等待。当一个 新任务需要运行时,如果线程池中有等待的工作的线程,就可以开始运行了;否 则进入等待队列。

为什么要用线程池:
       (1)减少了创建线程和销毁线程的次数,每个工作线程都可以被重复利用,可 以执行多个任务。
       (2)可以根据系统的承受能力,调整线程池中工作的线程的数目,防止因为消 耗过多的内存,导致服务器死机。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值