考点 - 操作系统 |
(进程、信号量、阻塞、UNIX文件系统、磁盘计算)
? 异步通信和同步通信的区别?
? 进程之间通信的方式有哪些?
? 操作系统临界资源访问的控制。
? Windows编程的知识点,如消息机制,一个自定义消息如何实现?
? 操作系统LRU算法
? 操作系统中由逻辑地址找物理地址。
? 文件索引问题。
? 死锁避免(最小资源分配)问题
? UNIX中文件的umask权限问题
? 操作系统执行可执行程序时,内存分配是怎样的?
? Linux后台开发问题。
? 操作系统:页式系统地址变换。
操作系统:缺页中断。
操作系统:资源调度与分配,计算CPU空闲时间。
操作系统:抖动(颠簸)的概念。
? 操作系统:linux的进程通信是怎样的吗?
? 读写问题。要怎么写优先。
? linux中查看当前进程列表的指令
? 操作系统中死锁是如何形成的
? 操作系统中最近最久未使用策略通过何种数据结构实现
? 文件模拟磁盘怎么设计?
? 怎么改变索引效率?
? 1、进程通信有哪几种方式?每种方式的特点是什么?
2、读写者问题的进程通信方式是怎样的?
服务器性能分析(CPU,内存,磁盘IO等影响因素)
? 计算机中的数字运算
? UTF-8 UTF-16中文编码。
计算机中的数字运算
操作系统临界资源访问的控制。
LIS问题的时空复杂度。
UTF-8 UTF-16中文编码。
操作系统:多线程编程:windows中的mutex,criticalsection。
死锁
银行家算法
1.基本知识点:
1) 操作系统是控制和管理计算机软硬件资源,以尽量合理有效的方法组织多个用户共享多种资源的程序集合。
2) 操作系统的基本功能:(1)处理机管理。主要功能包括进程控制、进程调度、进程同步和进程通信。(2)存储器管理。主要功能包括内存分配、地址映射、内存保护和内存扩充。(3)设备管,也叫I/O管理。主要功能包括缓冲区管理、设备分配、设备驱动和设备的无关性处理。(4)文件管理。主要功能包括文件存储空间的管理、文件操作的一般管理、目录管理、文件的读写管理和存取控制。(5)用户界面管理。操作系统的用户界面就是操作系统与用户的接口,包括控制接口和程序接口。
3) 现代操作系统的基本特征:并发性、共享性、虚拟性、异步性和不确定性。
4) 所谓中断是指系统发生某一事件后,CPU暂停正在执行的程序去执行处理该事件的程序过程,处理中断事件的程序称为中断处理程序,产生中断信号的那个部件称为中断源。中断处理具体过程:保存现场;分析原因,转中断处理程序;恢复现场。
5) 进程是一个具有独立功能的程序关于数据集合的一次可以并发执行的运行活动,其基本特征:动态特征、并发特征、独立性、相互制约性。进程的构成:程序、数据和进程控制块。进程有三种基本的调度状态:执行状态、就绪状态和等待状态。
6) 进程的引入大大地提高了资源的利用率和系统的吞吐量,而引入线程的目的是为了减少程序并发所付出的系统开销。进程是资源分配的单位,而线程是系统调度的单位。
7) 所谓死锁是多个进程间的一种僵持状态。进程死锁的原因:资源竞争及进程推进顺序非法。死锁的4个必要条件:互斥、占有等待、不可剥夺、环路。死锁的处理:鸵鸟策略、预防策略、避免策略、检测与解除死锁。
8) 临界资源是一次只允许一个进程使用的资源。临界区是在进程中操作临界资源的程序段。
2.进程和线程的区别?
答:线程是指进程内的一个执行单元,也是进程内的可调度实体.与进程的区别:(1)调度:线程作为调度和分配的基本单位,进程作为拥有资源的基本单位。(2)并发性:不仅进程之间可以并发执行,同一个进程的多个线程之间也可并发执行。(3)拥有资源:进程是拥有资源的一个独立单位,线程不拥有系统资源,但可以访问隶属于进程的资源. (4)系统开销:在创建或撤消进程时,由于系统都要为之分配和回收资源,导致系统的开销明显大于创建或撤消线程时的开销。
3.网络编程中设计并发服务器,使用多进程 与多线程 ,请问有什么区别?
解析:(1)进程:子进程是父进程的复制品。子进程获得父进程数据空间、堆和栈的复制品
(2)线程:相对与进程而言,线程是一个更加接近与执行体的概念,它可以与同进程的其他线程共享数据,但拥有自己的栈空间,拥有独立的执行序列。
两者都可以提高程序的并发度,提高程序运行效率和响应时间。线程和进程在使用上各有优缺点:线程执行开销小,但不利于资源管理和保护;而进程正相反。同时,线程适合于在SMP机器上运行,而进程则可以跨机器迁移。
答:用多进程时每个进程有自己的地址空间,线程则共享地址空间。所有其他区别都是由此而来的:(1)速度:线程产生的速度快,线程间的通信快,切换快等,因为它们在同一个地址空间内。(2)资源利用率:线程的资源利用率比较好也是因为它们在同一个地址空间内。(3)同步问题:线程使用公共变量/内存时需要使用同步机制,还是因为它们在同一个地址空间内。
4. 操作系统中常见的进程调度策略有哪几种?
答:FCFS(先来先服务),优先级,时间片轮转,多队列、多级反馈队列。
5.进程间的通信如何实现?
答:现在最常见的进程间通信的方式有:信号,信号量,消息队列,共享内存,管道。信号是使用信号处理器来进行的,信号量是使用P、V操作来实现的。消息队列是比较高级的一种进程间通信方法,因为它真的可以在进程间传送消息。
6.在Windows编程中互斥器(mutex)的作用和临界区(critical section)类似,请说一下二者间的主要区别。
答:两者的区别是mutex开业用于进程之间互斥,critical section是线程之间的互斥。
7.进程进入等待状态有哪几种方式?
答:CPU调度给优先级更高的Thread(线程),原先Thread 进入Waiting(等待)状态。阻塞的Thread获得资源或者信号,进入Waiting状态。在时间片轮转的情况下,如果时间片到了,也将进入等待状态。
8.试说明进程在三个基本状态之间转换的典型原因。
答:a.处于就绪状态的进程,当进程调度程序为之分配了处理机后,该进程便由就绪状态变为执行状态。b.当前进程因发生某事件而无法执行,如访问已被占有的临界资源,就会使进程由执行状态变为阻塞状态。c.当前进程因事件片用完而被暂停执行,该进程便由执行状态变为就绪状态。
9.同步机构应遵循哪些基本准则?
答:a.空闲让进;b.忙则等待;c.有限等待;d.让权等待。
10.在单处理机环境下,进程间有哪几种通信方式?
答:a.共享存储器系统通信方式;b.消息传递系统通信方式;c.管道通信方式。
11.试比较消息队列与管道通信机制。
答:a.所谓管道,是指用于连接一个读进程和一个写进程,以实现它们之间通信的共享文件,又称pipe文件,管道通信是属于共享存储系统的。b.消息队列通信机制属于消息传递系统通信机制,存在通信链路,有消息的格式,有若干缓冲队列,采用独特的发送原语和接受原语。
12.在请求分页系统中,常采用哪几种页面置换算法?
答:a.最佳置换算法;b.先进先出算法;c.最近最久未使用LRU置换算法;d.Clock置换算法;e.此外,还有最少使用置换算法和页面缓冲算法。
操作系统各大公司笔试题汇总 |
http://blog.csdn.net/hackbuteer1/article/details/6787354
1、在段页式存储管理中,其虚拟地址空间是()A、一维 B、二维 C、三维 D、层次
答案:B
2、采用( )不会产生内部碎片(“内零头”)
A、分页式存储管理 B、分段式存储管理
C、固定分区式存储管理 D、段页式存储管理
答案:B
3、段页式管理每取一数据,要访问()次内存。
A、1 B、2 C、3 D、4
答案:C
4、分段管理提供(B)维的地址结构。
A、1 B、2 C、3 D、4
二维逻辑地址:段号+段内地址
分页与分段的主要区别:
1)、段是信息的逻辑单位,它是根据用户的需要划分的,因此段对用户是可见的;页是信息的物理单位,是为了管理主存的方便而划分的,对用户是透明的。
2)、页的大小固定不变,由系统决定。段的大小是不固定的,它由其完成的功能决定。
3)、段式向用户提供的是二维地址空间,页式向用户提供的是一维地址空间,其页号和页内偏移是机器硬件的功能。
4)、由于段是信息的逻辑单位,因此便于存贮保护和信息的共享,页的保护和共享受到限制。
分页与分段存储管理系统虽然在很多地方相似,但从概念上讲,两者是完全不同的,它们之间的区别如下:
①页是信息的物理单位。分页的目的是实现离散分配,减少外部碎片,提高内存利用率。段是信息的逻辑单位。每一段在逻辑上是一组相对完整的信息集合。
②分页式存储管理的作业地址空间是一维的,而分段式存储管理的作业地址空间是二维的。
③页的大小固定且由系统确定,是等长的。而段的长度不定。
④分页的优点体现在内存空间的管理上,而分段的优点体现在地址空间的管理上。
5、()存储管理方式提供二维地址结构。
A、固定分区 B、分页 C、分段 D、可变分区
答案:C
6、()存储管理方式提供一维地址空间。
A、固定分区 B、分段 C、分页 D、分段和段页式
答案:A
7、下列()存储管理方式能使存储碎片尽可能少,而且使内存利用率较高。
A、固定分区 B、可变分区 C、分页管理 D、段页式管理
答案:D
8、分页管理每取一数据,要访问( )次内存。
A、1 B、2 C、3 D、4
答案:B
9、通道是一种()。
A、I/O端口 B、数据通道 C、I/O专用处理机 D、软件工具
答案:C
10、磁盘与主机之间的数据传送方式是( )
A、无条件 B、程序查询 C、中断方式 D、DMA方式
答案:D
11、在一个请求页式存储管理中,一个程序的页面走向为4、3、2、1、3、5、4、3、2、1、5,并采用LRU算法。设分配给该程序的存储块数M分别为3和4,在该访问中发生的缺页次数F和缺页率f 是(C )
A. ①M=3,F=8、f≈67% ②M=4,F=5、f≈42%
B.①M=3,F=10、f=83% ②M=4,F=8、f≈67%
C.①M=3,F=9、f≈75% ②M=4,F=9、f≈75%
D.①M=3,F=7、f≈58% ②M=4,F=6、f=50%
12、进程和程序的本质区别是( D)
A、存储在内存和外存 B、顺序和非顺序执行机器指令
C、分时使用和独占使用计算机资源 D、动态和静态特征
13、系统感知进程的唯一实体是(C )
A、JCB B、FCB C、PCB D、SJT
14、SPOOLING技术利用于( B)
A、外设概念 B、虚拟设备概念 C、磁带概念 D、存储概念
15、( A)是直接存取设备。
A、磁盘 B、磁带 C、打印机 D、键盘显示终端
16、采用假脱机技术,将磁盘的一部分作为公共缓冲区以代替打印机,用户对打印机的操作实际上是对磁盘的存储操作,用以代替打印机部分是指()
A、独占设备 B、共享设备 C、虚拟设备 D、一般物理设备
答案:C
17、在可变分区存储管理中的移动技术优点在于()
A、增加主存容量 B、缩短访问周期 C、加速地址转换 D、集中空闲区
答案:D
18、位示图的用处为()
A、主存空间的共享 B、文件的保护和加密 C、磁盘空间的管理 D、文件目录的查找
答案:C
19、虚拟设备中,当用户作业要进入系统时,由SPOOLing系统的预输入程序将作业信息从物理输入设备上送到( )
A、内存 B、输入井 C、输出井 D、通道
答案:B
20、设在内存中有P1、P2、P3三道程序,并按照P1、P2、P3的优先次序运行,其内部计算和I/O操作时间由下图给出:
P1:计算 60ms----------------I/O80ms-----------------计算 20ms
P2:计算 120ms--------------I/O 40ms-----------------计算 40ms
P3:计算 40ms----------------I/O80ms-----------------计算 40ms
调度程序的执行时间忽略不计,完成这三道程序比单道运行节省的时间是(C )
A、80ms B、120ms C、160ms D、200ms
解析:首先P1计算60ms,然后I/O 80ms,在这80ms中,P2也同步开始计算,等P1的I/O运行完了,CPU停止P2的计算,转去做P1后期那20ms的运算,至此所花时间为60+80+20=160ms;然后CPU再去接着运算P2,40ms,然后p2I/O运行40ms,在此期间,cpu去计算p3,正好也是40ms,算完之后接着算p2的后期部分,40ms,在此期间,因为p3的前40ms已经计算完成,可以进行i/o操作,所以同时p3的i/o也开始运行,运行80ms,这80ms中,前40msCPU在算P2,后40msCPU在算P3,所以是:40+40+40+80=200ms,加上前面的160,为360ms。
而如果是单道运行,则时间花费为:60+80+20+120+40+40+40+80+40=520ms,相差为520-360=160ms ,选C
产生死锁的原因主要是:
(1) 因为系统资源不足。
(2) 进程运行推进的顺序不合适。
(3) 资源分配不当等。
产生死锁的四个必要条件:
(1) 互斥条件:一个资源每次只能被一个进程使用。
(2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。
(3) 不剥夺条件:进程已获得的资源,在末使用完之前,不能强行剥夺。
(4) 循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。
这四个条件是死锁的必要条件,只要系统发生死锁,这些条件必然成立,而只要上述条件之一不满足,就不会发生死锁。
虚拟内存的概念 |
进程和线程的异同 |
操作系统概念:
进程和线程各自的优缺点:
一个程序至少有一个进程,一个进程至少有一个线程。
进程在执行过程中拥有独立的内存单元。而多个线程共享内存,从而提高了程序的运行效率。
进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动,进程是系统进行资源分配和调度的一个独立单位.
线程是进程的一个实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位.线程自己基本上不拥有系统资源,只拥有一点在运行中必不可少的资源(如程序计数器,一组寄存器和栈),但是它可与同属一个进程的其他的线程共享进程所拥有的全部资源.
进程和线程的主要差别在于它们是不同的操作系统资源管理方式。进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程之间没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。如果有兴趣深入的话,我建议你们看看《现代操作系统》或者《操作系统的设计与实现》。对就个问题说得比较清楚。
从调度,并发性,系统开销,拥有资源等四方面对其进行比较。
调度
线程为轻量级进程,是处理器CPU调度和分派的基本单元。
显著提高系统的并发性。
进程则作为资源拥有的基本单位。
并发性
不仅进程之间可以并发执行,而且一个进程中的多个线程之间也可以并发执行。更好并发性。
有效使用系统资源,提高系统吞吐量。
系统开销
进程都是拥有系统资源的一个独立单位。
线程共享进程的资源:代码段,数据段,系统资源。
拥有资源
进程切换占用昂贵的系统调用。
而线程切换只需保存和设置少量寄存器的内容。并不涉及存储器管理方面的操作。
进程是系统所有资源分配时候的一个基本单位,拥有一个完整的虚拟空间地址,并不依赖线程而独立存在。
为什么要引入线程的概念?
为了减少进程切换和创建的开销,提高执行效率和节省资源。
进程与线程:《操作系统》
在传统的操作系统中,进程拥有独立的内存地址空间和一个用于控制的线程。但是,现在的情况更多的情况下要求在同一地址空间下拥有多个线程并发执行。因此线程被引入操作系统。
这些进程中包含的其它迷你进程就是线程。
线程之所以说是迷你进程,是因为线程和进程有很多相似之处,比如线程和进程的状态都有运行,就绪,阻塞状态。这几种状态理解起来非常简单,当进程所需的资源没有到位时会是阻塞状态,当进程所需的资源到位时但CPU没有到位时是就绪状态,当进程既有所需的资源,又有CPU时,就为运行状态。
就拿我写博客的LiveWriter来说,LiveWriter需要监听我打字输入的状态,还需要每隔5分钟对草稿进行自动保存。假设如果这个进程只有一个线程的话,那么当对草稿进行保存时,因为此时需要访问硬盘,而访问硬盘的时间线程是阻塞状态的,这时我的任何输入都会没有响应,这种用户体验是无法接受的,或许我们可以通过键盘或者鼠标的输入去中断保存草稿的过程,但这种方案也并不讨好。而使用多线程,每个线程仅仅需要处理自己那一部分应该完成的任务,而不用去关心和其它线程的冲突。因此简化了编程模型。
更具体的说,线程的好处如下:
1.在很多程序中,需要多个线程互相同步或互斥的并行完成工作,而将这些工作分解到不同的线程中去无疑简化了编程模型。
2.因为线程相比进程来说,更加的轻量,所以线程的创建和销毁的代价变得更小。
3.线程提高了性能,虽然线程宏观上是并行的,但微观上却是串行。从CPU角度线程并无法提升性能,但如果某些线程涉及到等待资源(比如IO,等待输入)时,多线程允许进程中的其它线程继续执行而不是整个进程被阻塞,因此提高了CPU的利用率,从这个角度会提升性能。
4.在多CPU或多核的情况下,使用线程不仅仅在宏观上并行,在微观上也是并行的
而线程共享进程的内存地址空间。
进程是用于组织资源的单位,进程将相关的资源组织在一起,这些资源包括:内存地址空间,程序,数据等,将这些以进程的形式组织起来可以使得操作系统管理这些资源更为容易。
而线程,是每一个进程中执行的一个条线。线程虽然共享进程中的大多数资源,但线程也需要自己的一些资源,比如:用于标识下一条执行指令的程序计数器,一些容纳局部变量的寄存器,以及用于表示执行的历史的栈。
总而言之:进程是组织资源的最小单位,而线程是安排CPU执行的最小单位。
其实在一个进程中多个线程并行和在操作系统中多个进程并行非常类似,只是线程共享的是地址空间,而进程共享的是物理内存,打印机,键盘等资源
选择题 - 操作系统 |
24 进程进入等待状态有哪几种方式?(D)
A CPU调度给优先级更高的线程
B 阻塞的线程获得资源或者信号
C 在时间片轮转的情况下,如果时间片到了
D 获得spinlock未果
(计算机存储)
一次内存访问,SSD硬盘访问和SATA硬盘随机访问的时间分别是?
几十纳秒,几十微秒,几十毫秒。
SATA硬盘的概念?串口硬盘
在16位机器上跑下列foo函数的结果是(B)
void foo()
{
int i = 65536; 2^16 = 2^15+2^15 0
cout << i <<”,”;
i = 65535;
cout << i;
}
A、-1,65535 B、0,-1 C、-1,-1 D、0,65535
在5个页框上使用LRU页面替换算法(Least Recently Used 近期最少使用算法),当页框初始为空时,引用序列为0、1、7、8、6、2、3、7、2、9、8、1、0、2,系统将发生(C)次缺页
A、13 B、12 C、11 D、8
分析:缺页为:0、1、7、8、6、2、3、9、8、1、0,共11次
22、下列有关进程的说法中,错误的是(ABC)
A、进程与程序是一亿对应的 B、进程与作业时一一对应的
C、进程是静态的 D、进程是动态的过程
任何一个作业要执行的话必须经过两级调度,第一级为作业调度,作业调度把选中的作业装人主存储器后相应的进程应处于就绪状态;第二级为进程调度,处于就绪状态的作业进程只有被进程调度选中后才能占用处理器运行。一个作业在执行中要经历若干个作业步,每个作业步都是一个程序的执行,因而每个作业步都是一个进程,且这些进程执行时还会请求创建新的进程协助工作。因而,作业与进程并非是一一对应的。
文件分配表FAT是管理磁盘空间的一种数据结构,用在以链接方式存储文件的系统中记录磁盘分配和追踪空白磁盘块,整个磁盘仅设一张FAT表,其结构如下所示,如果文件块号为2,查找FAT序号为2的内容得知物理块2的后继物理块是5,再查FAT序号为5的内容得知物理块5的后继物理块是7,接着继续查FAT序号为7的内容为“Λ”,即该文件结束标志,
假设磁盘物理块大小为1KB,并且FAT序号以4bits为单位向上扩充空间。请计算下列两块磁盘的FAT最少需要占用多大的存储空间?
(1)一块540MB的硬盘 (2)一块1.2GB的硬盘
分析:(1)磁盘块大小为1KB,540MB的硬盘可以分成540MB/1KB=5.4*105个磁盘块,因此至少需要5.4*105<220个编号,需要20bit存储空间
(2)同理,1.2G至少需要1.2*106<221个编号,为21bit,由于FAT序号以4bits为单位向上扩充,因此需要24bit存储空间
linux下系统调用fork()面试题 |
http://blog.csdn.net/chdhust/article/details/10579001
秒杀linux下系统调用fork()面试题
第一道题(在之前博客也写过这道题:http://blog.csdn.net/chdhust/article/details/8535915):
题目:请问下面的程序一共输出多少个“-”?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include #include #include
int main(void) { int i; for(i=0; i<2; i++) { fork(); printf("-"); }
return 0; }
|
如果你对fork()的机制比较熟悉的话,这个题并不难,输出应该是6个“-”,但是,实际上这个程序会很tricky地输出8个“-”。
要讲清这个题,我们首先需要知道fork()系统调用的特性,
所以,上面的那个程序为什么会输入8个“-”,这是因为printf(“-”);语句有buffer,所以,对于上述程序,printf(“-”);把“-”放到了缓存中,并没有真正的输出,在fork的时候,缓存被复制到了子进程空间,所以,就多了两个,就成了8个,而不是6个。
另外,多说一下,我们知道,Unix下的设备有“块设备”和“字符设备”的概念,所谓块设备,就是以一块一块的数据存取的设备,字符设备是一次存取一个字符的设备。磁盘、内存都是块设备,字符设备如键盘和串口。块设备一般都有缓存,而字符设备一般都没有缓存。
对于上面的问题,我们如果修改一下上面的printf的那条语句为:
1 |
printf("-\n");
|
或是
1 2 |
printf("-"); fflush(stdout);
|
就没有问题了(就是6个“-”了),因为程序遇到“\n”,或是EOF,或是缓中区满,或是文件描述符关闭,或是主动flush,或是程序退出,就会把数据刷出缓冲区。需要注意的是,标准输出是行缓冲,所以遇到“n”的时候会刷出缓冲区,但对于磁盘这个块设备来说,“n”并不会引起缓冲区刷出的动作,那是全缓冲,你可以使用setvbuf来设置缓冲区大小,或是用fflush刷缓存。
我估计有些朋友可能对于fork()还不是很了解,那么我们把上面的程序改成下面这样:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
#include #include #include int main(void) { int i; for(i=0; i<2; i++){ fork(); //注意:下面的printf有“n” printf("ppid=%d, pid=%d, i=%d n", getppid(), getpid(), i); } sleep(10); //让进程停留十秒,这样我们可以用pstree查看一下进程树 return 0; }
|
于是,上面这段程序会输出下面的结果,(注:编译出的可执行的程序名为fork)
1 2 3 4 5 6 7 8 9 10 |
ppid=8858, pid=8518, i=0 ppid=8858, pid=8518, i=1 ppid=8518, pid=8519, i=0 ppid=8518, pid=8519, i=1 ppid=8518, pid=8520, i=1 ppid=8519, pid=8521, i=1
$ pstree -p | grep fork |-bash(8858)-+-fork(8518)-+-fork(8519)---fork(8521) | | `-fork(8520)
|
面对这样的图你可能还是看不懂,没事,我好事做到底,画个图给你看看:
注意:上图中的我用了几个色彩,相同颜色的是同一个进程。于是,我们的pstree的图示就可以成为下面这个样子:(下图中的颜色与上图对应)
这样,对于printf(“-”);这个语句,我们就可以很清楚的知道,哪个子进程复制了父进程标准输出缓中区里的的内容,而导致了多次输出了。(如下图所示,就是我阴影并双边框了那两个子进程)
第二道题:
给出如下C程序,在linux下使用gcc编译:
[objc] viewplaincopyprint?
要求如下:
已知从这个程序执行到这个程序的所有进程结束这个时间段内,没有其它新进程执行。
1、请说出执行这个程序后,将一共运行几个进程。
2、如果其中一个进程的输出结果是“pid1:1001, pid2:1002”,写出其他进程的输出结果(不考虑进程执行顺序)。
这里先列出一些必要的预备知识,对linux下进程机制比较熟悉的朋友可以略过。
1、进程可以看做程序的一次执行过程。在linux下,每个进程有唯一的PID标识进程。PID是一个从1到32768的正整数,其中1一般是特殊进程init,其它进程从2开始依次编号。当用完32768后,从2重新开始。
2、linux中有一个叫进程表的结构用来存储当前正在运行的进程。可以使用“ps aux”命令查看所有正在运行的进程。
3、进程在linux中呈树状结构,init为根节点,其它进程均有父进程,某进程的父进程就是启动这个进程的进程,这个进程叫做父进程的子进程。
4、fork的作用是复制一个与当前进程一样的进程。新进程的所有数据(变量、环境变量、程序计数器等)数值都和原进程一致,但是是一个全新的进程,并作为原进程的子进程。
有了上面的预备知识,我们再来看看解题的关键。我认为,解题的关键就是要认识到fork将程序切成两段。看下图:
上图表示一个含有fork的程序,而fork语句可以看成将程序切为A、B两个部分。然后整个程序会如下运行:
step1、设由shell直接执行程序,生成了进程P。P执行完Part. A的所有代码。
step2、当执行到pid = fork();时,P启动一个进程Q,Q是P的子进程,和P是同一个程序的进程。Q继承P的所有变量、环境变量、程序计数器的当前值。
step3、在P进程中,fork()将Q的PID返回给变量pid,并继续执行Part. B的代码。
step4、在进程Q中,将0赋给pid,并继续执行Part. B的代码。
这里有三个点非常关键:
1、P执行了所有程序,而Q只执行了Part. B,即fork()后面的程序。(这是因为Q继承了P的PC-程序计数器)
2、Q继承了fork()语句执行时当前的环境,而不是程序的初始环境。
3、P中fork()语句启动子进程Q,并将Q的PID返回,而Q中的fork()语句不启动新进程,仅将0返回。
解题
下面利用上文阐述的知识进行解题。这里我把两个问题放在一起进行分析。
1、从shell中执行此程序,启动了一个进程,我们设这个进程为P0,设其PID为XXX(解题过程不需知道其PID)。
2、当执行到pid1 = fork();时,P0启动一个子进程P1,由题目知P1的PID为1001。我们暂且不管P1。
3、P0中的fork返回1001给pid1,继续执行到pid2= fork();,此时启动另一个新进程,设为P2,由题目知P2的PID为1002。同样暂且不管P2。
4、P0中的第二个fork返回1002给pid2,继续执行完后续程序,结束。所以,P0的结果为“pid1:1001, pid2:1002”。
5、再看P2,P2生成时,P0中pid1=1001,所以P2中pid1继承P0的1001,而作为子进程pid2=0。P2从第二个fork后开始执行,结束后输出“pid1:1001, pid2:0”。
6、接着看P1,P1中第一条fork返回0给pid1,然后接着执行后面的语句。而后面接着的语句是pid2 = fork();执行到这里,P1又产生了一个新进程,设为P3。先不管P3。
7、P1中第二条fork将P3的PID返回给pid2,由预备知识知P3的PID为1003,所以P1的pid2=1003。P1继续执行后续程序,结束,输出“pid1:0, pid2:1003”。
8、P3作为P1的子进程,继承P1中pid1=0,并且第二条fork将0返回给pid2,所以P3最后输出“pid1:0, pid2:0”。
9、至此,整个执行过程完毕。
所得答案:
1、一共执行了四个进程。(P0, P1, P2, P3)
2、另外几个进程的输出分别为:
pid1:1001, pid2:0
pid1:0, pid2:1003
pid1:0, pid2:0
进一步可以给出一个以P0为根的进程树:
代码验证结果:
第三道题:
请补足横线,使之输出welcome xiyoulinux
if(_____)
printf(“xiyoulinux ”);
else
printf(“welcome”);
这道题如果在if中只写fork(),也不知道打印出来什么顺序的,所以想到函数wait(),等待子进程结束。
程序改写为:
运行结果:
可见这样才得到了正确的运行结果。
第四道题:
int main()
{
return fork()&&fork()||fork();
}
问题:1.一共产生几个进程 2.返回值为1的概率为多少?
这道题一看头都晕了,但是抓其根本,再难也都能解决的!!
其实对于fork的分析,最直观的做法也最有效,画出进程关系图,两个问题便迎刃而解
这里要用到的有关fork的知识并不多,只需要知道fork的返回值:fork是一次调用,两次返回;子进程的返回值为0,父进程的返回值是新产生子进程的进程号(大于0)。对于&&操作符,若前操作数为0,则直接跳过后操作数的判断。
基于以上两个基本理论,通过图示,即可得出结论:
图中同一色彩的框图代表同一进程,可见,此时共产生5个进程;结合表达式的最终值分布情况可得,返回1的概率为3/5
造成此种结果,最主要的诱因,是fork()后,父进程与子进程返回没有先后顺序,有时父进程先返回,有时子进程先返回。所以,根据父子进程返回的不同结果,逻辑运算符&&和||选择是否执行其后的程序代码(此处即为fork)。
第五道题(EMC的一道笔试题)
[cpp] viewplaincopyprint?
这道题和第四道题比较类似,第一个fork()和最后一个fork()一定会执行,中间的同上图,在这里不画了。
所以这道题解法为:加上前面的fork和最后的fork,所有的进程都会执行,会产生4个分支,总共4*5=20个分支,也就是20个进程,除去main主进程,就是19个进程了。
参考来源:
1. http://blog.csdn.net/chdhust/article/details/8535915
2. http://www.cnblogs.com/leoo2sk/archive/2009/12/11/talk-about-fork-in-linux.html
3. http://blog.csdn.net/u010940849/article/details/9624987
4. http://taingg.blog.163.com/blog/static/1197204832012101281321861/
5. http://bbs.chinaunix.net/thread-1947534-1-1.html
Linux进程和线程的区别(baidu 面试) |
http://blog.csdn.net/younger_china/article/details/9722981
进程是程序执行时的一个实例,即它是程序已经执行到课中程度的数据结构的汇集。从内核的观点看,进程的目的就是担当分配系统资源(CPU时间、内存等)的基本单位。
线程是进程的一个执行流,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。一个进程由几个线程组成(拥有很多相对独立的执行流的用户程序共享应用程序的大部分数据结构),线程与同属一个进程的其他的线程共享进程所拥有的全部资源。
"进程——资源分配的最小单位,线程——程序执行的最小单位"
进程有独立的地址空间,一个进程崩溃后,在保护模式下不会对其它进程产生影响,而线程只是一个进程中的不同执行路径。线程有自己的堆栈和局部变量,但线程没有单独的地址空间,一个线程死掉就等于整个进程死掉,所以多进程的程序要比多线程的程序健壮,但在进程切换时,耗费资源较大,效率要差一些。但对于一些要求同时进行并且又要共享某些变量的并发操作,只能用线程,不能用进程。
总的来说就是:进程有独立的地址空间,线程没有单独的地址空间(同一进程内的线程共享进程的地址空间)。(下面的内容摘自Linux下的多线程编程)
使用多线程的理由之一是和进程相比,它是一种非常"节俭"的多任务操作方式。我们知道,在Linux系统下,启动一个新的进程必须分配给它独立的地址空间,建立众多的数据表来维护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。而运行于一个进程中的多个线程,它们彼此之间使用相同的地址空间,共享大部分数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时间也远远小于进程间切换所需要的时间。据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,当然,在具体的系统上,这个数据可能会有较大的区别。
使用多线程的理由之二是线程间方便的通信机制。对不同进程来说,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。线程则不然,由于同一进程下的线程之间共享数据空间,所以一个线程的数据可以直接为其它线程所用,这不仅快捷,而且方便。当然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的打击,这些正是编写多线程程序时最需要注意的地方。
除了以上所说的优点外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,当然有以下的优点:
=============================
从函数调用上来说,进程创建使用fork()操作;线程创建使用clone()操作。Richard Stevens大师这样说过:
fork is expensive. Memory is copied from the parent tothe child, all descriptors are duplicated in the child, and so on. Currentimplementations use a technique called copy-on-write, which avoids a copy ofthe parent's data space to the child until the child needs its own copy. But,regardless of this optimization, fork is expensive.
IPC is required to pass information between the parentand child after the fork. Passing information from the parent to the childbefore the fork is easy, since the child starts with a copy of the parent'sdata space and with a copy of all the parent's descriptors. But, returninginformation from the child to the parent takes more work.
Threads help with both problems. Threads are sometimescalled lightweight processes since a thread is "lighter weight" thana process. That is, thread creation can be 10–100 times faster than process creation.
All threads within a process share the same globalmemory. This makes the sharing of information easy between the threads, butalong with this simplicity comes the problem
操作系统内存管理 - 分区、页式、段式管理 |
《操作系统内存管理——分区、页式、段式管理》http://blog.csdn.net/hguisu/article/details/5713164