linux课程设计报告.docx
- 文档编号:12846536
- 上传时间:2023-04-22
- 格式:DOCX
- 页数:21
- 大小:27.86KB
linux课程设计报告.docx
《linux课程设计报告.docx》由会员分享,可在线阅读,更多相关《linux课程设计报告.docx(21页珍藏版)》请在冰豆网上搜索。
linux课程设计报告
《Linux操作系统》课程设计报告
题目:
Linux对进程和线程的治理机制研究
所在院系:
软件学院
完成学生:
zhangsan运算机科学与技术
指导教师:
lisi
完成日期:
2012年6月6日
1.课程设计题目概述
Linux是一个多用户多任务的操作系统。
多用户是指多个用户能够在同一时刻利用运算机系统;多任务是指Linux能够同时执行几个任务,它能够在还未执行完一个任务时又执行另一项任务。
操作系统治理多个用户的请求和多个任务。
大多数系统都只有一个CPU和一个主存,但一个系统可能有多个二级存储磁盘和多个输入/输出设备。
操作系统治理这些资源并在多个用户间共享资源,当您提出一个请求时,给您造成一种假象,仿佛系统只被您独自占用。
而事实上操作系统监控着一个等待执行的任务队列,这些任务包括用户作业、操作系统任务、邮件和打印作业等。
操作系统依照每一个任务的优先级为每一个任务分派适合的时刻片,每一个时刻片大约都有零点几秒,尽管看起来很短,但事实上已经足够运算机完成成千上万的指令集。
每一个任务都会被系统运行一段时刻,然后挂起,系统转而处置其他任务;过一段时刻以后再回来处置那个任务,直到某个任务完成,从任务队列中去除。
Linux系统上所有运行的东西都能够称之为一个进程。
每一个用户任务、每一个系统治理守护进程,都能够称之为进程。
Linux用分时治理方式使所有的任务一起分享系统资源。
咱们讨论进程的时候,可不能去关切这些进程究竟是如何分派的,或是内核如何治理分派时刻片的,咱们所关切的是如何去操纵这些进程,让它们能够专门好地为用户效劳。
在Linux中,每一个进程在创建时都会被分派一个数据结构,称为进程操纵块(ProcessControlBlock,简称PCB)。
PCB中包括了很多重要的信息,供系统调度和进程本身执行利用,其中最重要的莫过于进程ID(processID)了,进程ID也被称作进程标识符,是一个非负的整数,在Linux操作系统中唯一地标志一个进程,在咱们最常利用的I386架构(即PC利用的架构)上,一个非负的整数的转变范围是0-32767,这也是咱们所有可能取到的进程ID。
其实从进程ID的名字就能够够看出,它确实是进程的身份证号码,每一个人的身份证号码都可不能相同,每一个进程的进程ID也可不能相同。
一个或多个进程能够合起来组成一个进程组(processgroup),一个或多个进程组能够合起来组成一个会话(session)。
如此咱们就有了对进程进行批量操作的能力,比如通过向某个进程组发送信号来实现向该组中的每一个进程发送信号。
2.研究内容与目的
Linux是一个多用户多任务的操作系统。
每一个用户任务、每一个系统治理守护进程,都能够称之为进程。
Linux用分时治理方式使所有的任务一起分享系统资源。
咱们讨论进程的时候,可不能去关切这些进程究竟是如何分派的,或是内核如何治理分派时刻片的,咱们所关切的是如何去操纵这些进程,让它们能够专门好地为用户效劳。
Linux进程治理仍是需要的,尽管在桌面应用上,咱们点鼠标就能够完成大多的工作,但在效劳器治理中,Linux进程治理仍是十分重要的。
Windows的Linux进程治理真的很方便,按一下CTRL+ALT+DEL就能够够调出来,随意你怎么杀和砍。
我感觉Windows的Linux进程治理并非怎么样,若是有的程序真的需要CTRL+ALT+DEL的话,呵,那确信会显现系统假死现象。
或程序错误之类的提示。
弄不行就得重启,这是事实。
Windows的Linux进程治理并非优秀,只是一个友好的界面罢了,Linux进程治理关于电脑利用的玩家的经常使用软件,然后我就学习及深切的研究Linux进程治理,参考了多方面的资料,在那个地址探讨Linux进程治理的利用方式
3.研究报告
一、进程的概念和分类
1.进程和线程的概念
Linux是一个多用户多任务的操作系统。
多用户是指多个用户能够在同一
时刻利用同一个linux系统;多任务是指在Linux下能够同时执行多个任务,更详细的说,linux采纳了分时治理的方式,所有的任务都放在一个队列中,操作系统依照每一个任务的优先级为每一个任务分派适合的时刻片,每一个时刻片很短,用户全然感觉不到是多个任务在运行,从而使所有的任务一起分享系统资源,因此linux能够在一个任务还未执行完时,临时挂起此任务,又去执行另一个任务,过一段时刻以后再回来处置那个任务,直到那个任务完成,才从任务队列中去除。
这确实是多任务的概念。
上面说的是单CPU多任务操作系统的情形,在这种环境下,尽管系统能够运行多个任务,可是在某一个时刻点,CPU只能执行一个进程,而在多CPU多任务的操作系统下,由于有多个CPU,因此在某个时刻点上,能够有多个进程同时运行。
进程的的大体概念是:
在自身的虚拟地址空间运行的一个独立的程序,从操作系统的角度来看,所有在系统上运行的东西,都能够称为一个进程。
需要注意的是:
程序和进程是有区别的,进程尽管有程序产生,可是它并非是程序,程序是一个进程指令的集合,它能够启用一个或多个进程,同时,程序只占用磁盘空间,而不占用系统运行资源,而进程仅仅占用系统内存空间,是动态的、可变的,关闭进程,占用的内存资源随之释放。
例如,用户在linux上打开一个文件、就会产生一个打开文件的进程,关闭文件,进程也随机关闭。
若是在系统上启动一个效劳,例如启动tomcat效劳,就会产生一个对应的java的进程。
而若是启动apache效劳,就会产生多个httpd进程。
进程是资源治理的最小单位,线程是程序执行的最小单位。
在操作系统设计上,从进程演化出线程,最要紧的目的确实是更好的支持SMP和减小(进程/线程)上下文切换开销。
,一个进程至少需要一个线程作为它的指令执行体,进程治理着资源(比如cpu、内存、文件等等),而将线程分派到某个cpu上执行。
一个进程固然能够拥有多个线程,现在,若是进程运行在SMP机械上,它就能够够同时利用多个cpu来执行各个线程,达到最大程度的并行,以提高效率;同时,即便是在单cpu的机械上,采纳多线程模型来设计程序,正如昔时采纳多进程模型代替单进程模型一样,使设计更简练、功能更完备,程序的执行效率也更高,例如采纳多个线程响应多个输入,而现在多线程模型所实现的功能事实上也能够用多进程模型来实现,而与后者相较,线程的上下文切换开销就比进程要小多了,从语义上来讲,同时响应多个输入如此的功能,事实上确实是共享了除cpu之外的所有资源的。
在Linux系统下,启动一个新的进程必需分派给它独立的地址空间,成立众多的数据表来保护它的代码段、堆栈段和数据段,这是一种"昂贵"的多任务工作方式。
而运行于一个进程中的多个线程,它们彼此之间利用相同的地址空间,共享大部份数据,启动一个线程所花费的空间远远小于启动一个进程所花费的空间,而且,线程间彼此切换所需的时刻也远远小于进程间切换所需要的时刻。
据统计,总的说来,一个进程的开销大约是一个线程开销的30倍左右,固然,在具体的系统上,那个数据可能会有较大的区别。
利用多线程的理由之二是线程间方便的通信机制。
对不同进程来讲,它们具有独立的数据空间,要进行数据的传递只能通过通信的方式进行,这种方式不仅费时,而且很不方便。
线程那么不然,由于同一进程下的线程之间共享数据空间,因此一个线程的数据能够直接为其它线程所用,这不仅快捷,而且方便。
固然,数据的共享也带来其他一些问题,有的变量不能同时被两个线程所修改,有的子程序中声明为static的数据更有可能给多线程程序带来灾难性的冲击,这些正是编写多线程程序时最需要注意的地址。
除以上所说的优势外,不和进程比较,多线程程序作为一种多任务、并发的工作方式,固然有以下的优势:
1)提高应用程序响应。
这对图形界面的程序尤其成心义,当一个操作耗时很长时,整个系统都会等待那个操作,现在程序可不能响应键盘、鼠标、菜单的操作,而利用多线程技术,将耗时长的操作(timeconsuming)置于一个新的线程,能够幸免这种为难的情形。
2)使多CPU系统加倍有效。
操作系统会保证当线程数不大于CPU数量时,不同的线程运行于不同的CPU上。
3)改善程序结构。
一个既长又复杂的进程能够考虑分为多个线程,成为几个独立或半独立的运行部份,如此的程序会利于明白得和修改。
2.进程的分类
依照进程的功能和运行的程序分类,进程可划分为两大类:
系统进程:
能够执行内存资源分派和进程切换等治理工作;而且,该进程的运行不受用户的干与,即便是root用户也不能干与系统进程的运行。
用户进程:
通过执行用户程序、应用程序或内核之外的系统程序而产生的进程,此类进程能够在用户的操纵下运行或关闭。
针对用户进程,又能够分为交互进程、批处置进程和守护进程三类。
交互进程:
由一个shell终端启动的进程,在执行进程中,需要与用户进行交互操作,能够运行于前台,也能够运行在后台。
批处置进程:
该进程是一个进程集合,负责按顺序启动其他的进程。
守护进程:
守护进程是一直运行的一种进程,常常在linux系统启动时启动,在系统关闭时终止。
它们独立于操纵终端而且周期性的执行某种任务或等待处置某些发生的事件。
例如httpd进程,一直处于运行状态,等待用户的访问。
还有常经常使用的crond进程,那个进程类似与windows的打算任务,能够周期性的执行用户设定的某些任务。
3.进程的属性
(1)进程的几种状态
进程在启动后,不必然马上开始运行,因此进程存在很多种状态。
可运行状态:
处于这种状态的进程,要么正在运行、要么正预备运行。
可中断的等待状态:
这种进程处于阻塞状态,一旦达到某种条件,就会变成运行态。
同时该状态的进程也会由于接收到信号而被提早唤醒进入到运行态。
不中断的等待状态:
与“可中断的等待状态”含义大体类似,唯一不同的是处于那个状态的进程对信号不做响应。
僵死状态:
也确实是僵死进程,每一个进程在终止后都会处于僵死状态,等待父进程挪用进而释放资源,处于该状态的进程已经终止,可是它的父进程尚未释放其系统资源。
暂停状态:
说明现在的进程临时停止,来接收某种特殊处置,
(2)进程之间的关系
在linux系统中,进程ID(用PID表示)是区分不同进程的唯一标识,它们的大小是有限制的,最大ID为32768,用UID和GID别离表示启动那个进程的用户和用户组。
所有的进程都是PID为1的init进程的后代,内核在系统启动的最后时期启动init进程,因此,那个进程是linux下所有进程的父进程,用PPID表示父进程。
下面是通过ps命令输出的sendmail进程信息:
[root@localhost~]#ps-ef|grepsendmail
UIDPIDPPIDCSTIMETTYTIMECMD
root361410Oct23?
00:
00:
00sendmail:
acceptingconnections
相关于父进程,就存在子进程,一样每一个进程都必需有一个父进程,父进程与子进程之间是治理与被治理的关系,当父进程停止时,子进程也随之消失,可是子进程关闭,父进程不必然终止。
若是父进程在子进程退出之前就退出,那么所有子进程就变成的一个孤儿进程,若是没有相应的处置机制的话,这些孤儿进程就会一直处于僵死状态,资源无法释放,现在解决的方法是在启动的进程内找一个进程作为这些孤儿进程的父进程,或直接让init进程作为它们的父进程,进而释放孤儿进程占用的资源。
二、进程的数据结构与其生命周期
(1)底层数据结构:
双向链表
在进程治理中,双向链表是一个基础性的数据结构(后面涉及到的运行队列和等待队列等都利用了那个数据结构)。
它的声明如下(尽管名称中含有head,但事实上每一个结点都是相同的):
structlist_head{
structlist_head*next,*prev;
};
其中含有指向前一节点和后一节点的指针。
而作为双向链表,提供的要紧操作确实是添加/删除元素、遍历链表(专门是list_for_each()函数很重要,能够对每一个元素采取相同的操作)。
(2)进程描述符
进程描述符是一个名为task_struct的C结构(进程也确实是任务,因此叫task),其中包括了进程所有的信息。
其中有几个成员变量是咱们下面将要用到的(图顶用小黑框标出):
run_list,tasks。
(点击那个地址看大图)
(3)双向链表与宿主的结合
咱们回忆一下,若是咱们需要实现二叉树数据结构,那么往往需要先实现其树节点的数据结构(含有左右子节点的指针),而且一样是包括在二叉树内部;高级的数据结构需要先实现底层的数据结构。
咱们将二叉树等这一类高级的数据结构称为“宿主”,其中包括有底层数据结构的节点。
Linux内核中也可不能直接应用双向链表这种数据结构,可是确实在很多地址都需要链表的接口,于是也采纳了这种宿主与节点的模式。
这事实上是面向对象设计中的组合,实现了代码复用和降低了耦合性。
具体代码实现如下:
咱们此刻明白list成员是能够添加/删除元素、遍历的,可是如何才能遍历所有
的foo对象或foo对象中的data成员呢?
内核采纳了一个技术,即明白宿主对象的首地址和某成员相对首地址的偏移,就能够明白某成员的地址了,然后就能够掏出相应的值。
表示成公式确实是:
首地址+某成员偏移=某成员地址
structfoo{
intdata;
structlist_headlist;
};
如此的简单代码用过C语言的也应该都写过:
#include
typedefstruct_test
{chari;
intj;
chark;
}Test;
intmain()
{Test*p=0;printf("%p\n",&(p->k));}
那个地址就能够够打印出成员k相关于首地址的偏移。
固然,上面的公式移项就能够够换一种利用方式,已知某成员地址及其偏移量,即可求出宿主的首地址。
内核中事实上利用的是几个宏来具体计算:
offsetof()/container_of()/typeof()。
其中typeof()宏确实是取得其参数的类型,是由GCC编译器提供的。
#defineoffsetof(TYPE,MEMBER)((size_t)&((TYPE*)0)->MEMBER)
#definecontainer_of(ptr,type,member)({\
consttypeof(((type*)0)->member)*__mptr=(ptr);\
(type*)((char*)__mptr-offsetof(type,member));})
那个地址唯一需要说明的确实是offsetof宏中的(size_t)&((TYPE*)0)->MEMBER语句:
(TYPE*)0其实确实是相当于上面例子代码中的Test*p=0语句,将0看做一个地址,然后通过转型为TYPE型的指针,就创建了一个起始地址为0的TYPE型的对象,然后用&掏出其MEMBER成员的地址,转化成以size_t为单位的偏移字节量。
最终咱们拥有了已知某成员即可取得宿主及其成员变量的方式,如此也确实是说最终宿主也拥有了添加/删除成员、遍历的接口。
(4)双向链表与进程的结合实例:
进程链表,运行队列与等待队列
那个地址所说的进程链表(见《深切》p.93)是指把系统中所有的进程都串起来的链表。
利用了进程描述符中的tasks字段,那个字段是list_head型。
运行队列那么是将所有状态为TASK_RUNNING的进程(可运行进程,即可被调度马上执行的进程)串接起来的链表。
由于2.6版的内核采纳了新的调度系统,所有的可运行进程依照优先级被串在了140个不同的队列中(即共有140个高低不同的优先级)。
利用的是进程描述符中的run_list字段。
等待队列是指状态为TASK_INTERRUPTIBLE和TASK_UNINTERRUPTIBLE的进程的组织方式。
它的底层数据结构也是双向链表。
其头结点和一般节点的声明如下(重要字段用粗体标出):
struct__wait_queue_head{
spinlock_tlock;
structlist_headtask_list;
};
struct__wait_queue{
unsignedintflags;
structtask_struct*task;
wait_queue_func_tfunc;
structlist_headtask_list;
};
咱们能够看到不管是头结点仍是一般节点仍然通过包括一个list_head来实现串接,可是明显的与上面谈到的两个队列不同的是:
(a)队头节点中含有自旋锁(具体缘故请自行查阅);(b)等待队列不是包括在进程描述符中,而是在队列节点中包括了进程描述符task字段。
(5)进程哈希表pidhash及其中的链表
上面咱们说到的数据结构都是链表,可是咱们在进程治理中也用到一个hash表。
什么缘故要利用hash表呢?
因为咱们在linux中常常会用到此类操作:
给出进程号pid,要求取得进程描述符(例如kill()系统挪用,参数为pid,可是函数要去改变进程描述符中的state字段)。
若是咱们在进程队列中遍历然后看其pid是不是为所需的pid,如此做效率是很低的。
而hash确实是一个以空间换时刻的方式。
具体的hash函数就不写了(见《深切》p.97)。
可是那个地址仍然利用了一个链表,是因为凡是hash表,就会发生冲突(因为咱们一样可不能利用一一对应的hash表,那个地址所用的hash表一样是2048项,但系统中的进程往往能够最大到32767项)。
冲突的解决方式采纳了分离链接法:
即将所有冲突的项都串联到一个表项上,于是形成了链表。
理论上会形成2048个链表,可是大体上冲突的概率比较小,因此链表都可不能很长。
(6)进程的生命周期
进程的生命周期本章里面要紧包括:
创建、切换、撤销(调度将在第七章)。
而这些功能要紧都是由一些wrapper模式的内核函数实现的。
创建:
clone()挪用do_fork(),do_fork()再挪用copy_process()。
切换:
switch_to()宏
撤销:
exit_group()挪用do_group_exit()终止整个线程组;exit()挪用do_exit()终止单个的线程。
三、进程的监控与治理
Linux下,监控和治理进程的命令有很多,下面咱们以ps、top、pstree、lsof四个最经常使用的指令介绍若是有效的监控和治理linux下的各类进程。
2.1利用ps命令监控系统进程
ps是linux下最经常使用的进程监控命令,关于ps命令的语法和利用选项,咱们
在第四章已经有了详细的讲解,那个地址重点讲述如何利用ps指令监控和治理系统进程。
请看下面的例如:
下面是apache进程的输出信息
[root@localhost~]#ps-ef|grephttpd
UIDPIDPPIDCSTIMETTYTIMECMD
nobody7272260370Nov06?
00:
00:
00/apache2/bin/httpd-kstart
nobody7274260370Nov06?
00:
00:
00/apache2/bin/httpd-kstart
nobody7400260370Nov06?
00:
00:
00/apache2/bin/httpd-kstart
nobody750826037000:
09?
00:
00:
00/apache2/bin/httpd-kstart
nobody751326037000:
09?
00:
00:
00/apache2/bin/httpd-kstart
nobody751526037000:
09?
00:
00:
00/apache2/bin/httpd-kstart
nobody1199826037011:
14?
00:
00:
00/apache2/bin/httpd-kstart
nobody1294126037016:
25?
00:
00:
00/apache2/bin/httpd-kstart
nobody1297926037016:
44?
00:
00:
00/apache2/bin/httpd-kstart
root2603710Oct23?
00:
00:
00/apache2/bin/httpd-kstart
其中,UID是用户的ID标识号,PID是进程的标识号,PPID表示父进程,STIME
表示进程的启动时刻,TTY表示进程所属的终端操纵台,TIME表示进程启动后累计利用的CPU总时刻,CMD表示正在执行的命令。
从中能够清楚的看出,父进程和子进程的对应关系,PPID为26037的所有进程均为子进程,而PID为26037的进程是所有子进程的父进程,子进程由nobody用户启动,而父进程由root用户启动,父进程对应的PPID为1,即父进程同时为init进程的子进程。
其实也能够通过下面的指令方式查看子进程与父进程的对应关系,请看如下操作:
[root@localhost~]#psauxf|grephttpd
USERPID%CPU%MEMVSZRSSTTYSTATSTARTTIMECOMMAND
root260370.00.163162884?
SsOct230:
00/apache2/bin/httpd-kstart
nobody72720.00.170163740?
SNov060:
00\_/apache2/bin/httpd-kstart
nobody72740.00.170163704?
SNov060:
00\_/apache2/bin/httpd-kstart
nobody74000.00.170123676?
SNov060:
00\_/apache2/bin/httpd-kstart
nobody75080.00.170123732?
S00:
090:
00\_/apache2/bin/httpd-kstart
nobody75130.00.170123700?
S00:
090:
00\_/apache2/bin/httpd-kstart
nobody129790.00.170163684?
S16:
440:
00\_/apache2/bin/httpd-kstart
nobody129800.00.170123652?
S16:
440:
00\_/apache2/bin/httpd-kstart
nobody129820.00.170163664?
S16:
440:
00\_/apache2/bin/httpd-kstartnobody226640.00.168803540?
S22:
240:
00\_/apache2/bin/httpd-kstart
其中,%CPU表示进程占用的CPU百分比,%MEM表示进程占用内存的百
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- linux 课程设计 报告