一. 实验目的 了解Linux系统,熟悉Linux系统基础操作 了解Linux系统下C语言程序的编写和编译过程 了解Linux系统下的编译工具Make 理解fork函数的使用,掌握如何创建子进程。 理解wait函数的功能,掌握如何等待子进程结束。 二. 实验环境及材料 2.1 硬件环境配置 CPU: 13th Gen Intel(R) Core(TM) i9-13900HX,4核(每个核1个线程),基础频率2419.200 MHz,L1缓存:192 KiB(数据),128 KiB(指令);L2缓存:8 MiB;L3缓存:36 MiB。 内存: 总计1.9 GiB,已用959 MiB,空闲98 MiB,缓冲/缓存870 MiB,可用808 MiB。 硬盘: 总容量: 20 GiB 分区: /boot/efi:512 MiB /:19.5 GiB 挂载点: /media/elena/Ubuntu 20.04.2.0 LTS amd64(光盘驱动器,2.7 GiB) 2.2 软件名称、版本号及参数配置 操作系统: Linux 仿真软件: VMware Workstation 17Pro 三. 实验内容 3.1 实验设计 1.装机:参考以下两个网站,完成VMware Workstation 17Pro虚拟机的安装,并在虚拟机安装Ubuntu20.04 https://zhuanlan.zhihu.com/p/685829787https://blog.csdn.net/qq_45657288/article/details/116084337 2.熟悉Linux系统常用命令:15条基本操作语句 3.在Linux系统下尝试编写和编译C语言程序:编写一个简单的C程序,并用gcc命令执行 4.使用Linux系统下的编译工具Make:编写头文件greeting.h,自定义函数greeting.c,主函数myapp.c构成的C程序,根据这三个文件的依赖关系编写Makefile文件 5.编写并编译实验2代码示例。运行程序并观察输出,理解 fork 和 wait 的行为;分析程序输出,验证父子进程的工作独立性。 3.2 实验实施 3.2.1 Linux系统基础操作 参照网站,完成虚拟机以及Ubuntu安装,测试网络,成功ping通,表示已正常安装。 下图是装机成功后画面, 输入设定的用户密码后进入系统,显示桌面。 
Linux系统最重要的是“终端”,终端既可以通过“显示应用信息”打开, 
也可以通过快捷键“ctrl+alt+t”打开。 命令打破了使用Windows时一个鼠标“一点到底”的简单乏味, 它提供给用户更大的灵活性与想象空间,已成为Linux的魅力所在。 下面熟悉该系统。 1.Linux文件系统 Windows操作系统的设计初衷是单用户操作系统,而Unix和Linux操作系统的设计初衷是多用户操作系统。 
Ubuntu没有盘的概念,只有一个根目录/ ,所有文件都在它下面。 
2.Linux主要目录 (1)/根目录 在linux下有且只有一个根目录 (2)/home系统默认的用户家目录 (3)/etc系统配置文件存放的目录 (4)/bin保存可执行二进制文件的目录,如常用的ls、tar、mv、cat等。 3.Linux基础命令 终端命令格式: command [-options] [parameter] command:命令名 [-options]:选项,可对命令进行控制,也可省略 [parameter]:传给命令的参数,也可省略 command --help 显示command命令的帮助信息 【注】: .代表当前目录 . .代表上一级目录 4.Linux常用的15个基础命令 (1).cd命令 功能:change directory,改变工作目录 cd | 切换到当前用户的主目录(/home/用户目录) | cd . | 保持当前目录不变 | cd . . | 上级目录 | cd - | 可以在最近两次目录之间来回切换 |

(2)pwd命令 功能:print work directory,显示当前工作目录的绝对路径 (3)mkdir命令 功能:make directory,创建新的文件夹test 
(4)ls命令功能:list,列出目录的全部内容 
(5)touch命令功能:touch,如果文件不存在,则创建新的文件;如果文件存在,则修改文件的修改日期 (6)mv命令功能:move,移动文件,也可给文件或目录重命名(7)cp命令功能:copy,拷贝 
(8)rm命令功能:remove,删除文件或文件夹,不能恢复 (9)sudo命令功能:substitute user do用于提升用户权限,以管理员方式运行 sudo su -切换至管理员 (10)clear命令功能:clear,清屏 
(11)tree命令功能:tree,以树状图列出文件目录结构 
(12)cat命令功能:concatenate,查看文件内容、创建文件、文件合并、追加文件内容等功能 (13)more命令功能:more,分屏显示文件内容,每次只显示一页内容 (14)grep命令功能:grep,文本搜索工具 (15)echo命令功能:echo,在终端中显示参数指定的文字 
3.2.2 Linux系统下C语言程序的编写和编译 Linux中包含了很多软件开发工具。它们中的很多是用于C和C++应用程序开发的。 C是一种能在UNIX的早期就被广泛使用的通用编程语言。它最早是由Bell实验室的Dennis Ritchie为了UNIX的辅助开发而写的,从此C就成为世界上使用最广泛的计算机语言。 C能在编程领域里得到如此广泛支持的原因有: (1)它是一种非常通用的语言,并且它的语法和函数库在不同的平台上都是统一的,对开发者非常有吸引力; (2)用C写的程序执行速度很快; (3)C是所有版本UNIX上的系统语言; 1.打开编辑器,写代码Linux系统上有很多编辑器我们可以去直接使用,首先,我们打开命令提示符 Ctrl+Alt+T 然后输入 gedit main.c (表示打开编辑器,编辑一个名字为main.c的文件) 
此时我们已经进入到main.c文件上面,这时候我们可以去编写C语言了,下面写了一个C语言的简单加减乘除计算器。写完了之后点击保存。 
此时我们点开主目录后,会看到这里有一个main.c的文件。 
2.编译运行文件 Linux上可用的C编译器是GNUC编译器,它建立在自由软件基金会编程许可证的基础上,因此可以自由发布。 Linux上的GNUC编译器(GCC)是一个全功能的ANCIC兼容编译器,而一般UNIX(如SCOUNIX)用的编译器是CC。下面介绍GCC和一些GCC编译器最常用的选项。 (1)使用GCC 通常后跟一些选项和文件名来使用GCC编译器。GCC命令的基本用法如下: gcc [options] [filenames] 命令行选项指定的编译过程中的具体操作 (2)GCC常用选项 GCC有超过100个的编译选项可用,这些选项中的许多可能永远都不会用到,但一些主要的选项将会频繁使用。很多的GCC选项包括一个以上的字符,因此必须为每个选项指定各自的连字符,并且就像大多数LINUX 命令一样不能在一个单独的连字符后跟一组选项。例如,下面的命令是不同的: gcc-p-gtest.c gcc-pgtest.c 第一条命令告诉GCC编译test.c时为prof命令建立剖析(profile)信息并且把调试信息加入到可执行文件里。第二条命令告诉GCC只为gprof命令建立剖析信息。 当不用任何选项编译一个程序时,GCC将建立(假定编译成功)一个名为a.out的可执行文件。例如, gcctest.c 编译成功后,当前目录下就产生了一个a.out文件。 也可用-o选项来为即将产生的可执行文件指定一个文件名来代替a.out。例如: gcc–ocountcount.c 此时得到的可执行文件就不再是a.out,而是count。 GCC也可以指定编译器处理步骤多少。-c选项告诉GCC仅把源代码编译为目标代码而跳过汇编和连接步骤。这个选项使用得非常频繁因为它编译多个C程序时速度更快且更易于管理。默认时GCC建立的目标代码文件有一个.o的扩展名。 (3)执行文件 格式:./可执行文件名 例:./a.out ./count 保存了C语言文件之后,我们直接去通过gcc指令去编译运行文件,然后再通过./ 的方式来去执行结果。首先输入 gcc -o main main.c 指令,表示编译运行,此时会生成一个执行文件main 然后输入 ./main表示执行文件main。然后根据代码进行输入输出结果。 
3.2.3 Linux系统下的编译工具Make 打开终端,用touch命令创建文件 依次编写三个文件中的内容: 
创建Makefile文件,用于编译一个包含两个源文件(myapp.c 和 greeting.c)的 C 程序,定义了生成可执行文件 myapp 的规则,并通过 clean 命令清理编译生成的中间文件。 
使用make和./myapp语句执行,可以看到执行结果(中间出现语法错误,打开调整即可)。 
这样就成功使用make工具进行了编译。 3.2.4 进程的创建 1.用touch命令创建文件 
2.编写代码示例 (1)使用 fork 函数创建进程(fork01.c) 
(2)分离父子进程工作内容(fork02.c) 
(3)使用 wait 函数等待子进程(fork03.c) 
(4)父进程也加入计算内容(fork04.c) 
3.编译代码 
4.运行程序并观察输出 (1)fork01 
父进程和子进程的地址空间在创建时是相同的,但对共享变量的修改(如MyStr)在父子进程中是独立的。 输出中可看到父进程和子进程的pid,以及它们各自输出的内容,这表明它们是独立执行的。 (2)fork02 
在此示例中,父进程和子进程被分配了不同的任务,分别由ChildProcess和ParentProcess函数执行。 输出表明,子进程和父进程的输出是交错的,显示了它们在执行过程中的并行性。 (3)fork03 
该示例演示了父进程如何使用wait()函数等待子进程结束。父进程在两个子进程结束后输出相应的消息。 wait()函数确保父进程在子进程执行完毕后再继续执行,有助于管理子进程的生命周期。 (4)fork04 
在此示例中,父进程在子进程运行时也执行计算任务(查找阿姆斯特朗数)。父子进程并行执行各自的任务。 输出显示了父进程的计算结果,并在最后输出所有子进程结束的消息。 5.通过这个实验,可以体会出fork和wait函数各自的作用: (1)fork函数: 创建子进程:fork函数用于创建一个新进程(子进程),它是调用进程(父进程)的副本。子进程继承了父进程的资源,包括内存、打开的文件描述符等,但它们的执行是独立的。 返回值的判断:fork返回值的不同用于区分父进程和子进程: 在父进程中,返回的是子进程的PID(进程ID)。 在子进程中,返回值为0。 若返回值为负值,则表示创建子进程失败。 并行执行:父进程和子进程是并行执行的,输出结果可能会交错,显示它们的并发性。这种特性使得程序可以同时处理多个任务,提高效率。 (2)wait函数: 进程同步:wait函数用于阻塞父进程,直到一个或多个子进程结束。这是进程间同步的一种方式,确保父进程在继续执行之前等待子进程的完成,避免出现孤儿进程。 获取子进程状态:通过wait函数,父进程可以获取子进程的退出状态,帮助判断子进程是否正常结束或是否出现错误。这对于错误处理和资源管理至关重要。 资源回收:使用wait可以有效地回收子进程的资源,防止内存泄漏和资源浪费。这对于系统的稳定性和性能都非常重要。 3.3 实验数据分析 实验中遇到错误如下: 1.rm、cp等涉及移动文件的命令执行时,会出现路径错误,这是由于路径未指代或指代不明造成的 2.执行tree命令报错,依照提示安装即可 3.使用make编译时出现中间报错,经查是由于语法错误 四、实验思考 在本次实验中,我全面学习了Linux系统的基础操作,深入了解了Linux系统下的C语言编程流程,并掌握了Makefile这一强大的编译工具。通过实际动手操作,我对Linux系统的命令行有了更深刻的理解,感受到其灵活性和强大功能,尤其是在编译和构建过程中,命令行工具提供了极大的便利。 在Linux系统基础操作方面,我掌握了虚拟机VMware Workstation 17 Pro的安装和Ubuntu 20.04的配置,成功搭建起了实验环境。通过学习和实践Linux的常用命令,如cd、pwd、mkdir、ls、touch、mv、cp、rm、sudo、clear、tree、cat、more、grep和echo等,我能够高效地在Linux系统中进行文件管理和目录导航。这些基础命令的学习和使用,为我后续的实验操作打下了坚实的基础。 在Linux系统下的C语言编程方面,我学习了如何在Linux环境中编写、编译和运行C语言程序。通过GCC编译器,我能够将C语言源代码编译成可执行文件,并通过终端运行这些程序。在这个过程中,我深刻体会到了C语言作为一种高效、通用的编程语言在UNIX和Linux系统中的广泛应用。此外,我还学习了如何使用Makefile来管理C语言程序的编译过程,Makefile能够自动化地处理文件间的依赖关系,极大地提高了编译效率。 在进程的创建和管理方面,我通过编写和使用fork和wait函数,深入理解了Linux系统中进程的创建和同步机制。fork函数用于创建一个新进程(子进程),它是调用进程(父进程)的副本。通过fork函数,我能够并行地执行多个任务,提高了程序的执行效率。而wait函数则用于阻塞父进程,直到一个或多个子进程结束,从而确保父进程在继续执行之前等待子进程的完成。这种进程同步机制对于避免孤儿进程、回收子进程资源以及提高系统的稳定性和性能都非常重要。 在实验过程中,我也遇到了一些问题和挑战。例如,在执行rm、cp等涉及文件移动的命令时,由于路径指代不明或错误,导致命令无法正确执行。此外,在执行tree命令时,由于系统中未安装该命令,需要按照提示进行安装。在使用make编译时,也出现过语法错误等问题。这些问题和挑战促使我不断查阅相关资料和文档,加深对Linux系统和C语言编程的理解。 |