大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案_第1页
大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案_第2页
大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案_第3页
大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案_第4页
大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案_第5页
已阅读5页,还剩17页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

大学本科计算机类专业“操作系统原理”课程实验一:系统调用与进程初探导学案

  一、学情分析与教学理念定位

  本导学案面向大学本科计算机科学与技术、软件工程等相关专业二年级下学期的学生。此时,学生已完成《程序设计基础》、《数据结构》、《计算机组成原理》及《C语言程序高级编程》等先修课程的学习,具备了扎实的编程功底、对计算机系统底层硬件(如CPU、内存、中断)的基本认知,并初步掌握了多文件编程、编译链接过程及调试技能。然而,学生对“操作系统”这一核心系统软件的理解大多仍停留在理论层面,对于用户程序如何与操作系统内核交互、操作系统如何管理和抽象硬件资源缺乏直观和深切的体验。这种理论与实践的脱节,是深入理解操作系统原理的主要障碍。

  基于此,本次实验教学秉持“做中学、探中悟”的建构主义理念,并融合当前工程教育认证所倡导的“OBE(成果导向教育)”和“CDIO(构思-设计-实现-运行)”思想。教学核心目标不仅是完成几个孤立的实验步骤,更是引导学生经历一次完整的“系统观”构建之旅:从用户空间(UserSpace)的应用程序出发,主动“叩响”内核空间(KernelSpace)的大门,通过“系统调用”这一关键桥梁,亲手“触摸”操作系统对“进程”这一核心抽象概念的管理与控制。教学设计强调“问题驱动”和“认知冲突”,通过设计层层递进的探究任务,让学生在调试、观察、对比、分析中主动发现问题、提出假设、验证结论,从而将抽象的“进程控制块”、“地址空间”、“上下文切换”等概念转化为具体可感知的编程体验和运行现象,最终实现从“代码编写者”到“系统思考者”的视角升华。

  二、教学目标

  依据布鲁姆教育目标分类学,本次实验的教学目标设定为以下三个维度:

  1.知识与技能维度

  (1)能够准确阐述系统调用(SystemCall)在操作系统中的角色、作用及其与普通库函数(LibraryFunction)、应用程序编程接口(API)的异同与联系。

  (2)能够复现并解释在Linux环境下,使用C语言进行标准I/O(如printf

)和底层文件I/O(如write

)时,用户空间与内核空间的控制流与数据流传递过程。

  (3)能够熟练使用strace

工具跟踪并分析一个简单程序执行过程中所发生的系统调用序列,并解读关键参数和返回值。

  (4)能够准确编写C程序,正确使用fork()

、getpid()

、getppid()

、exec

函数族等系统调用创建和管理进程。

  (5)能够清晰描述fork()

调用后父子进程在内存空间、文件描述符、程序计数器等方面的异同(写时Copy-On-Write机制),并能通过程序输出验证这些特性。

  (6)能够区分进程创建(fork

)与程序加载执行(exec

)的本质区别,并能将其组合使用,实现指定的进程行为。

  2.过程与方法维度

  (1)经历“观察现象->提出猜想->设计实验验证->分析结果->修正理论”的完整科学探究过程,培养严谨的计算机系统实证研究能力。

  (2)掌握在Linux环境下,综合运用gcc

、gdb

、strace

、ps

、pstree

等工具进行程序编译、调试、动态跟踪和系统状态观察的工程方法。

  (3)学会阅读Linuxman

手册中关于系统调用的详细说明(特别是NOTES

和BUGS

章节),培养自主获取权威技术文档的能力。

  (4)通过分析fork()

与exec

的多种使用模式,培养在系统编程中构建复杂解决方案的分解与组合思维能力。

  3.情感、态度与价值观维度

  (1)激发对操作系统底层机制的好奇心与探索欲,体验“揭开系统神秘面纱”的智力乐趣。

  (2)培养系统编程中的“边界意识”与“敬畏之心”,理解不当使用系统调用(如fork

炸弹)可能带来的系统风险,树立安全、稳健的编程伦理观。

  (3)通过克服实验中遇到的编译错误、逻辑错误和与预期不符的运行结果,锤炼坚韧不拔的调试意志和精益求精的工程师精神。

  (4)初步建立“资源管理”和“抽象”的系统思维,认识到操作系统作为资源管理者的复杂性与精巧性,为后续学习内存管理、文件系统、并发控制等奠定坚实的认知基础。

  三、教学重点与难点

  教学重点:

  1.系统调用的边界跨越体验:让学生通过编程和工具跟踪,亲眼看到、亲手实现从用户态到内核态的切换,深刻理解系统调用是用户程序请求操作系统服务的唯一正当途径。

  2.fork()

系统调用的语义与行为:理解fork()

“一次调用,两次返回”的独特语义,以及由此产生的父子进程关系、资源共享与隔离的具体表现,这是理解进程模型的基础。

  3.fork()

与exec

的分离与协同:掌握进程创建与程序加载这两个独立操作的概念,并学会将其灵活组合,这是实现复杂进程行为(如Shell执行命令)的核心模式。

  教学难点:

  1.对“进程镜像”和“写时”的具象化理解:学生难以凭空想象fork()

后内存空间的实际情况。需要设计精巧的实验,通过观察变量地址、修改共享数据等操作,配合对copy-on-write

原理的讲解,将抽象机制具体化。

  2.exec

函数族对进程上下文的“覆盖”效应:理解exec

调用成功后,原进程的代码、数据、堆栈被全新程序替换,但某些属性(如进程ID、文件描述符表等)得以保留的“部分重生”概念,容易产生混淆。

  3.多进程执行时序的非确定性带来的调试挑战:由于操作系统调度器的介入,父子进程、多个子进程间的执行顺序是不确定的。学生需要学会分析这种并发性初始形态,理解使用wait()

/waitpid()

进行同步的必要性,并应对由此带来的非确定性输出问题。

  四、教学资源与环境

  1.软件环境:

  *操作系统:推荐使用原生Linux发行版(如Ubuntu22.04LTS,CentOSStream)或Windows/macOS下的Linux虚拟机(VirtualBox/VMware+标准Linux镜像)及WSL2(WindowsSubsystemforLinux2)。确保内核版本在4.x以上。

  *开发工具链:gcc

(C编译器)、gdb

(GNU调试器,带-g

编译选项)、make

(工程管理)。

  *系统观察与跟踪工具:strace

(系统调用跟踪器)、ltrace

(库调用跟踪器)、ps

、pstree

、top

/htop

(进程状态查看)。

  *文档:Linuxman

手册(需安装mans

包)。在线资源如POSIX标准文档索引作为拓展。

  2.实验材料包(预置代码):

  *demo_hello.c

:一个简单的“HelloWorld”程序,用于strace

分析入门。

  *demo_file_io.c

:分别使用stdio

库函数(fprintf

)和POSIX

系统调用(write

)进行文件写入的对比程序。

  *template_fork_basic.c

:包含基础框架的fork()

示例,学生需补充代码以观察父子进程行为。

  *template_fork_advanced.c

:设计用于探究变量地址、数据修改等高级特性的实验模板。

  *template_exec_demo.c

:展示exec

函数族(execl

,execv

,execvp

等)不同用法的模板。

  *challenge_mini_shell.c

:一个极简的Shell骨架,作为高阶挑战任务,要求学生填充fork

-exec

-wait

循环。

  3.引导性文档:

  *《实验一:前置知识自查清单》.

  *《strace

核心参数与输出解读指南》.

  *《fork()

与exec

的man

手册精读要点》.

  五、教学实施过程(总计约6-8学时)

  第一阶段:课前预习与知识唤醒(线上,1学时)

  任务驱动:

  1.知识自查:学生需完成《前置知识自查清单》,回顾C语言指针、数组、字符串、结构体;复习编译命令gcc-o-g

;了解Shell基础命令(cd

,ls

,cat

,grep

)。

  2.文献预读:阅读教材中关于操作系统接口、系统调用概念、进程定义与状态的章节。观看一段约15分钟的微视频,展示一个简单命令(如ls

)在Linux中从键入到输出结果的全过程中,涉及的大致系统活动(终端读取、解析、fork

、exec

、文件系统访问、写终端)。

  3.环境准备:确保个人实验环境(Linux虚拟机或实体机)中的开发工具和必要软件包安装就位,并能成功编译运行一个简单的C程序。

  4.预习思考题:

    (1)你认为printf("Hello");

这条语句执行时,计算机硬件和软件具体做了哪些事情?“Hello”这个字符串是如何最终显示在屏幕上的?

    (2)什么是“进程”?一个正在运行的程序和存储在磁盘上的可执行文件有什么本质区别?

    (3)如果让你设计一个功能,使一个程序能“分裂”出另一个和自己几乎一模一样的副本,你会考虑哪些信息?哪些信息必须不同?

  第二阶段:课中导学与深度探究(线下实验室,4-5学时)

  【环节一:创设情境,问题导入(约20分钟)】

  教师活动:不以直接讲解概念开始,而是现场演示两个“魔法”现象。

  *现象A:快速编写并运行一个调用fork()

的简单程序,屏幕上打印出令人困惑的、看似“混乱”但又具规律的多行输出。提问:“程序明明只调用了一次printf

,为什么输出了多次?这些输出顺序是固定的吗?为什么?”

  *现象B:打开两个终端,在一个终端运行一个死循环程序(while(1);

),在另一个终端立刻用ps

和pstree

命令展示其进程信息及父子关系。提问:“这个‘失控’的程序是如何被操作系统管理和标识的?ps

命令本身也是一个程序,它如何‘知道’其他程序的信息?这些信息从哪里来?”

  学生活动:观察现象,分组讨论,提出初步假设。教师引导学生将问题聚焦到“程序如何与操作系统对话”(系统调用)和“操作系统如何表示运行中的程序”(进程)这两个核心议题上。由此自然引出本次实验的两个核心主题。

  【环节二:第一主题探究——揭开系统调用的面纱(约70分钟)】

  *步骤1:概念辨析(10分钟)。教师以“餐厅顾客(用户程序)与后厨(操作系统内核)”为类比,精讲API、库函数、系统调用的层次关系。强调:系统调用是穿越用户/内核边界(“提交点餐单”)的唯一方式;库函数(如printf

)是对一个或多个系统调用的封装(“服务员”),可能添加缓冲等逻辑。明确“glibc

”作为Linux下主要C库的角色。

  *步骤2:工具初探——strace

(25分钟)。学生动手实验。

    (1)编译运行demo_hello.c

。使用strace./demo_hello

观察输出。初始输出信息庞大,教师引导学生关注关键列:系统调用名称、参数(尤其是文件描述符数字、指针值)、返回值。

    (2)使用strace-otrace.log-T-tt./demo_hello

将跟踪结果输出到文件,并包含时间戳和耗时。指导学生用grep

过滤出write

、brk

、mmap

等关键调用。

    (3)核心探究任务:对比分析demo_file_io.c

中,使用fprintf

写文件和write

写文件的两段代码,分别用strace

跟踪。观察:

      a.fprintf

路径下,除了write

,还多了哪些系统调用?(如open

,fstat

,mmap

,mprotect

等)。思考这些调用是谁发起的?为何需要它们?(链接库、打开标准库内部所需文件等)

      b.write

路径下,系统调用序列简单很多。思考write

的第一个参数fd

(文件描述符)是如何得来的?(来自之前的open

调用)。

    (4)小组讨论与分享:每组总结“一次标准输出(屏幕)写入”和“一次文件写入”所经历的系统调用路径,并尝试绘制简要的数据流图。教师巡回指导,解答关于参数含义、错误返回值(-1

)的疑问。

  *步骤3:概念深化与小结(5分钟)。教师总结:strace

让我们“看见”了用户程序与内核的对话。每一次系统调用都是一次上下文切换,有一定开销。系统调用的存在,使得操作系统能够对所有资源访问进行统一的监控、管理和保护,这是操作系统实现其管理职能的基石。

  【环节三:第二主题探究——进程的诞生与演变(约120分钟)】

  *步骤1:进程的创建——fork()

的奥秘(50分钟)。

    (1)基础认知:教师讲解fork()

的经典语义:“调用一次,返回两次”。在父进程中返回子进程PID,在子进程中返回0。这是区分父子进程执行流的关键。强调fork()

了父进程的几乎整个上下文。

    (2)实验1:基本行为观察。学生完善并运行template_fork_basic.c

。任务包括:打印父子进程的PID、PPID;观察全局变量、局部变量在fork

前后的值;尝试在父子进程中分别修改同一个全局变量,观察结果。

    (3)实验2:深入探究“”的真相(难点突破)。学生使用template_fork_advanced.c

      a.地址观察:打印父子进程中同一个全局变量、同一个动态分配内存(malloc

)的地址。发现它们虚拟地址相同。教师引入“虚拟地址空间”概念,解释fork

了页表,使得父子进程虚拟地址指向开始时相同的物理页。

      b.写时(COW)验证:在父或子进程中修改该全局变量的值,然后再次打印父子进程中的该变量值及其地址。发现值不同了,但地址依然相同。此时产生认知冲突。教师揭示COW机制:当任一进程试图写入共享页时,内核会透明地为其一个新物理页,并修改页表映射。这个过程对程序是透明的,但可以通过观察内存实际变化(需更高级工具)或通过/proc/[pid]/smaps

查看私有脏页来间接感知。此环节是理解现代操作系统内存管理优化和进程隔离的关键。

      c.文件描述符的共享:在fork

前打开一个文件,在父子进程中分别写入。观察文件内容。理解文件描述符表也被,导致父子共享同一打开文件句柄(文件偏移量共享)。引出进程间通信(IPC)的雏形。

    (4)进程树观察:编写一个产生多级fork

的程序,使用pstree-p

直观查看生成的进程树状结构。理解进程的层级关系。

  *步骤2:进程的蜕变——exec

的使命(40分钟)。

    (1)概念讲解:教师强调exec

的功能是“加载一个新程序到当前进程的地址空间并执行”,它取代了当前进程的文本、数据、堆和栈段,但保留了进程ID、打开的文件描述符、信号处理设置等属性。fork

与exec

通常是“黄金搭档”:fork

负责克隆一个执行环境,exec

负责在这个新环境中运行目标程序。

    (2)实验3:exec

函数族使用。学生操作template_exec_demo.c

,尝试使用execl

,execvp

等不同变体来执行/bin/ls

等简单命令。重点理解参数列表(l

vsv

)和环境变量(p

)传递方式的区别。

    (3)关键探究:在fork

出的子进程中调用exec

执行一个新程序(如/bin/echo

),在父进程中用wait

等待。观察:

      a.子进程exec

后,其PID是否改变?(不变)

      b.如果子进程exec

失败(例如指定一个不存在的程序路径),会发生什么?(exec

返回-1,子进程继续执行exec

后的代码)。这强调了错误检查的重要性。

  *步骤3:进程的同步——wait

的必要性(20分钟)。

    (1)问题引出:运行一个不包含wait

的多次fork

程序,观察其输出顺序的混乱,并与加入wait

后的有序输出对比。直观感受异步执行带来的不确定性。

    (2)原理讲解:wait

/waitpid

系统调用使父进程阻塞,直到一个子进程状态改变(终止或停止)。这不仅用于回收子进程资源(防止僵尸进程),也是简单的进程间同步机制。

    (3)实验4:僵尸进程与回收。编写一个让子进程先退出、父进程睡眠数秒后再退出的程序。在睡眠期间,使用psaux|grepdefunct

观察僵尸进程(状态为Z

)的存在。修改程序,让父进程在子进程退出后立即调用wait

,再观察僵尸进程是否消失。

  【环节四:综合应用与挑战(约60分钟)】

  *任务:实现一个简易Shell的核心循环(challenge_mini_shell.c

)。

    学生需在提供的骨架代码上,填充一个循环,该循环:

    1.打印提示符(如mysh>$

)。

    2.读取用户输入的命令(简化:使用fgets

读取一行)。

    3.解析命令和参数(简化:假设命令不带选项,用空格分隔,使用strtok

)。

    4.子进程:调用execvp

执行该命令。

    5.父进程:调用wait

等待子进程结束,然后继续循环。

  *拓展思考:

    *如何支持带路径的命令?

    *如何实现内置命令(如cd

、exit

)?(exec

不会执行这些,因为它们需要改变Shell自身状态)。

    *如何支持后台运行(在命令末尾加

)?(父进程不wait

,但需注意防止僵尸进程,可忽略SIGCHLD

信号或异步等待)。

  *教师在此环节作为教练,提供思路点拨,鼓励学生查阅资料、结对编程,解决实现过程中遇到的具体问题。完成基础功能后,可鼓励学有余力的学生尝试上述拓展。

  【环节五:课堂总结与反思(约15分钟)】

  *邀请1-2个小组分享他们在探究过程中最深刻的发现或遇到的最大挑战及其解决方法。

  *教师进行结构化总结,将本次实验的零散知识点串联起来,形成概念图:

    用户程序--(通过API/库函数)-->发起系统调用--(陷入内核)-->操作系统内核提供服务(如创建进程fork

、加载程序exec

、等待子进程wait

)-->管理进程实体(PCB、地址空间、文件表)-->抽象出“进程”概念给用户。

  *强调:系统调用是接口,进程是管理单元。理解它们,就拿到了理解操作系统如何工作的第一把钥匙。

  第三阶段:课后拓展、报告撰写与评价(线下,1-2学时)

  1.拓展任务(选做):

  *使用clone()

系统调用(参数控制共享程度)创建“线程”(轻量级进程),并与fork()

创建的传统进程在资源开销、共享数据方面进行简单对比。

  *研究vfork()

与fork()

的历史区别与现状(vfork

的风险和现代fork

的COW优化使其几乎过时)。

  *尝试编写一个程序,使其成为“进程监视器”,定期(如每秒)使用ps

或直接读取/proc

文件系统信息,监控并报告系统中指定进程的状态变化。

  2.实验报告要求:

  报告不鼓励罗列代码和步骤,而是强调分析与思考。必须包含:

  *核心问题回答:针对预习思考题,结合实验给出更深入的答案。

  *实验现象记录与分析:对strace

跟踪stdio

和POSIXI/O

的差异进行对比分析;对fork()

后父子进程的变量地址、值的变化给出合理解释(结合COW);描述并解释fork-exec-wait

模式在简易Shell中的工作流程。

  *遇到的问题与解决方案:详细描述1-2个调试过程中遇到的关键问题及其解决思路。

  *创新与思考:对实验的任何改进建议,或由实验引发的对操作系统设计的新疑问。

  3.评价方式:

  采用过程性评价与结果性评价相结合。

  *过程性评价(40%):课堂参与度、探究活动的完成质量、小组讨论贡献、挑战任务完成情况。

  *结果性评价(60%):实验报告的深度、逻辑性、分析的准确性及创新性思考。

  六、教学评价与反馈设计

  1.形成性评价贯穿全程:

  *课前:预习清单完成情况,作为了解学生基础的依据。

  *课中:通过提问、小组讨论分享、教师巡视时对代码和观察结果的即兴抽查,实时评估学生对概念的理解和工具使用的熟练度。利用“课堂快问”小程序,在关键知识点后设置1-2道选择题(如“fork()

后,以下哪项不是被子进程继承的?”),即时收集反馈,调整教学节奏。

  *课后:实验报告是核心的形成性评价载体,重点关注其分析论证过程。

  2.总结性评价:

  以实验报告为主,评价学生对核心知识的内化程度和系统思维能力。

  3.反馈机制:

  *实验报告批改后,提供个性化评语,指出亮点与不足,并推荐针对性拓展阅读。

  *针对实验报告中反映出的共性问题(如对exec

失败处理普遍忽视、对COW理解仍模糊),在下一堂课开始时进行集中讲评与澄清。

  *设立线上论坛(如课程讨论区),鼓励学生分享实验心得、奇技淫巧和疑难问题,形成持续的学习共同体。

  七、教学反思与改进

  (此为教师专用部分,预设可能出现的挑战及迭代方向)

  *预期挑战:学生Linux环境配置问题可能耗时;gdb

与strace

的初始学习曲线较陡;对并发非确定

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论