操作系统学习报告

仅供自己学习查看,如需使用请复制到Lunix系统上查看…不知道为什么win上排版会乱…
操作系统实验报告

目录

实验二 Linux基础 2
实验三 编辑器vi和编译器gcc的使用 4
实验四 进程管理实验 10
实验五 进程和线程同步 12
实验六 进程间通信 18
实验七 存储器管理 25
实验八 Linux文件系统 32

实验二 Linux基础
实验日期: 2022.4.12 报告分:
实验目的:
研习并掌握Linux的基础指令,了解 Linux 系统,熟悉 Linux 文件和目录。
预习报告:
预习了Linux 文件系统结构,cat指令、ls指令等。
Linux 文件系统是树状结构的,系统中每个分区都是一个文件系统,都有自己的目录层次。Linux 会将这些分属不同分区的、单独的文件系统按照树状的方式形成一个系统的总目录层次结构。目录提供了一个管理文件方便而有效的途径,最上层是根目录,其它所有目录都是从根目录出发而生成的。如图 2-1 所示。微软的 DOS 和 Windows 也是采用树状结构,但是 DOS 和 Windows 中这样的树状结构的根是磁盘分区的盘符,有几个分区就有几个树状结构,它们之间的关系是并列的。但是在 Linux 系统中,无论操作系统管理几个磁盘分区,这样的目录树都只有一个。
实验观测记录及数据处理:
Ls指令:-a 列出目录下的所有文件,包括以 . 开头的隐含文件。
-d 将目录象文件一样显示,而不是显示其下的文件。
-i 输出文件的 i 节点的索引信息。
-k 以 k 字节的形式表示文件的大小。
-r 对目录反向排序。
-s 在每个文件名后输出该文件的大小。
-R 递归地显示指定目录的各个子目录中的文件。
-l 以长格式列出文件的详细信息。这个选项最常用。每行显示的信息依次为文件的类型与权限、链接数、文件属主、文件属组、文件大小、建立或最近修改的时间和文件名。文件类型与权限为由 10 个字符构成的字符串表示,其中第一个字符表示文件类型,包括-(普通文件)、d(目录)、l(符号)、b(块设备文件)和 c(字符设备文件)。

Pwd指令:显示当前路径

Touch指令:当前路径新建文件

Cd指令:cd 进入用户主目录,cd ~ 进入用户主目录,cd - 返回进入此目录之前所在目录,cd … 返回上一级目录,cd …/… 返回上两级目录,cd !$ 把上个命令的参数作为cd 参数使用,cd / 进入根目录,cd . 当前目录

Ls指令:对于目录,该命令列出该目录下的所有子目录与文件。对于文件,将列出文件名以及其他信息。
ls -a 列出目录下的所有文件,包括以.开头的隐含文件。ls -d将目录象文件一样显示,而不是显示其下的文件。只显示当前文件夹;ls -l显示文件详细信息;ls -t是以最后一次修改时间排序
cd进入bin目录ls查看(太多了塞不下,截取一部分)

Cd /返回上一级

Cd进入home,ls查看当前路径下文件

Ps指令:ps命令是Process Status的缩写。ps命令用来列出系统中当前运行的那些进程。

Ps -aux查看详情(太多了截取部分)

Su指令:su的作用是变更为其它使用者的身份,超级用户除外,需要键入该使用者的密码。我们无法直接通过cd进入root文件夹,想要进入需要权限,因此需要使用su指令。

Vi指令:vi编辑器是所有Unix及Linux系统下标准的编辑器。实验中从touch文件开始学习vi指令。

回车后输入q进入编辑模式,输入hellow后,按Esc退出编辑模式
Cat指令:cat 是一个文本文件查看和连接工具。查看一个文件的内容,用cat比较简单,就是cat 后面直接接文件名.

Cat指令还可以cat 文件名 >新文件名,用于新建一个文件并将内容复制给新文件,cat 文件名1 文件名2 >新文件名,用于新建一个文件并将文件1和2内容复制给新文件

Chmod命令:主要用于修改、设置文件权限

rm命令:删除文件且不可逆

mkdir 指令:可以实现在指定位置创建以 指定的文件名 命名的文件夹或目录。(与touch类似)

date 指令:显示时间数据

who 指令:查看用户

实验题目:用who 命令显示当前正在你的Linux系统中使用的用户名字:

  1. 有多少用户正在使用你的Linux系统?给出显示的结果

  2. 哪个用户登录的时间最长?给出该用户登录的时间和日期。

使用下面的命令显示有关你计算机系统信息:uname(显示操作系统的名称), uname –n(显示系统域名),uname –p(显示系统的CPU名称)

  1. 你的操作系统名字是什么?

  2. 你计算机系统的域名是什么?

  3. 你计算机系统的CPU名字是什么?

使用passwd命令修改你用whoami命令找到用户名。然后使用who -a命令来看 看你的用户名和同一系统其他用户的列表的登录密码。

在shell提示符后,输入echo $PS1并按回车键,系统怎样回答?

在shell提示符后,输入PS1=%并按回车键,显示屏有什么变化?

在shell提示符后,输入set 并按回车键,系统显示环境变量。

给出你系统中 的环境变量和它的值。 本实验用到的命令还有:date、cal、pwd、write、uptime、man等。

  1. 登录你的Linux系统。

  2. 用命令date显示当前的时间,给出显示的结果。

  3. 用cal命令显示下列年份的日历:4、52、1752、1952、2005、2006
    a) 给出你显示以上年份年历的命令

b) 1752年有几天,为什么?提示:在因特网上查找答案
cal 指令源自美国 AT&T 的 UNIX,也因此继承了美国的历史。时间回到 1752 年。1752年9月大英帝国极其所属美洲殖民地的恺撒历法被格里高利教皇历法所取代。由于恺撒历法比格里高利历法迟11天,因此9月2日当天改历法后,次日须为9月14日,结果是9月3日到13日成了历史绝对空白期!
4. 用pwd显示你的主目录(home directory)名字,给出pwd显示的结果。

  1. 使用alias 命令显示系统中的命令的别名,给出显示的结果。

  2. 使用uptime 命令判断系统已启动运行的时间和当前系统中有多少登录用 户,给出显示的结果。

    1. 通过因特网或Linux的man命令得到下面的shell命令、系统调用和库函数功能描述及每个命令使用例子:
      Command Short Description Example Use
      touch 新建文件 touch 1
      cp 复制文件和目录 cp 1.txt /home/
      mv 移动文件或目录、重命名文件或目录 mv /root/zhao/testdir0 /root/zhao/targetdir/
      rm 删除文件 rm 1.txt
      mkdir 创建目录 mkdir 1
      rmdir 删除目录 rmdir 1
      ls 列出目前工作目录所含之文件及子目录 Ls
      cd 更改当前路径 cd …
      pwd 显示当前路径 pwd
      open 打开文件 open -e test.txt
      read 标注输入读取数值 read -a array
      write 实现用户间信息传递 write user1 pts/1
      close 底层文件操作 close_demo.c
      pipe 管道命令 ls | cat > dirinfo
      socket 套接字 socket():
      mkfifo 创建FIFO mkfifo [OPTION]… NAME…
      system 系统命令 system(“pause”)
      printf 打印 Printf(”1”)

实验三 编辑器vi和编译器gcc的使用
实验日期: 2022.4.20 报告分:
实验目的:
掌握编辑器 vi 的基本操作,能够用 vi 来编辑 C 语言源程序;学会 indent 的 用法;掌握用 gcc 来做一些简单的编译。
预习报告:
预习了vi编辑器的使用方法,vi编辑器有三种模式:命令模式(command mode)、插入模式(Insert mode)、底行模式(last line mode)。
vi 简介:vi 是 Unix 世界里极为普遍的全屏幕文书编辑器,几乎可以说任何一台 Unix 机器都会提供这套软件。当你熟悉 DOS 下的文书处理后,也许会感到vi 并不好用;Unix 上也已经发展出许多更新、更好用的文书编辑器,但是并不一定每一台 Unix 机器上都会安装这些额外的软件。所以,学习 vi 的基本操作还是有好处的,让你在各个不同的机器上得心应手。只要简单的执行 vi 就可以进入 vi 的编辑环境。在实际操作之前先对它有个概略的了解会比较好。vi 有两种模式,输入模式以及指令模式。输入模式即是用来输入文字资料,而指令模式则是用来下达一些编排文件、存档、以及离开 vi 等等的操作指令。当执行 vi 后,会先进入指令模式,此时输入的任何字符都视为指令。
vi的两种模式:
命令模式:当vi打开时默认为命令模式,要转入输入模式,需要按a或者i键。在命令模式下,此时键盘上输入的所有东西都被vi当作命令来对待。
在命令模式下,最好不要乱输入。此时应该输入相应的命令,来让vi做相应的事。
输入模式:输入模式用来向文件输入内容。可以从命令模式中按a或者i进入输入模式。进入输入模式后,就可以随意按键盘进行输入了。输入完成后如果要保存,要先退回到命令模式(因为保存也是一种命令)。在输入模式下按ESC键退回到命令模式。
在命令模式下如何保存:
:wq 保存并且退出
:w 只保存不推出
:q 不保存退出 进来看了一下没改退出
:q! 不保存强制退出
:wq! 保存并强制退出
实验观测记录及数据处理:
Touch新建一个文件myfile,进入 vi执行如下命令$vi myfile ,屏幕显示 vi 的编辑窗口,进入命令操作模式。按下a或者i回车进入输入模式,如果在输入模式下,则先利用 Esc 键进入命令模式,而后即可选用下列命令退出 vi。(注意:如果不知道现在是处于什么模式,可以多按几次 Esc 键,系统会发出哔哔声以确定进入命令模式。)

:q! 离开 vi,并放弃刚才编辑的内容。
:wq 存盘并退出。
:ZZ 存盘并退出。
:x 若有修改存盘,并退出程序
:w 存盘并不退出。
:q 退出 vi,若文件被修改过,则会被要求确认是否放弃修改的内容。(此指令可与 w 配合使用。)

常见的 vi 命令如下表所示(并未列全)
移动光标类命令:h :光标左移一个字符, l :光标右移一个字符 space:光标右移一个字符,Backspace:光标左移一个字符,k 或 Ctrl+p:光标上移一行 j 或 Ctrl+n :光标下移一行,KaTeX parse error: Expected '}', got 'EOF' at end of input: …Enter :光标下移一行,n:光标移至第 n 行尾, }:光标移至段落开头。
插入文本类命令:i :在光标前, I :在当前行首 ,a:光标后,o:在当前行之下新开一行 A:在当前行尾 nCC:修改指定数目的行,O:在当前行之上新开一行 ,R:替换当前字符及其后的字符,直至按 ESC 键,s:从当前光标位置处开始,以输入的文本替代指定数目的字符,r:替换当前字符, S:删除指定数目的行,并以所输入文本代替之,ncw 或 nCW:修改指定数目的字。
删除类命令:ndd:删除当前行及其后 n-1行,do:删至行首 d$:删至行尾,ndw 或 ndW:删除光标处开始及其后的 n-1 个字,x 或 X:删除一个字符,x 删除光标后的,而 X 删除光标前的,Ctrl+u:删除输入方式下所输入的文本。
末行类命令::n1,n2 co n3:将n1 行到n2 行之间的内容拷贝到第n3 行下,:n1,n2 m n3:将n1 行到n2 行之间的内容移至到第n3 行下,:n1,n2 d :将 n1 行到 n2 行之间的内容删除,:w :保存当前文件, : e filename :打开文件filename 进行编辑,:x:保存当前文件并退出,:q:退出 vi :q!:不保存文件并退出 vi :!command:执行 shell 命令command:, r!command : 将 命令command 的输出结果放到当前行,:n1,n2 w!command:将文件中 n1 行至 n2 行的内容作为command 的输入并执行之,若不指定 n1,n2,则表示将整个文件内容作为 command 的输入。
indent 实用程序 indent 实用程序是 Linux 里包含的另一个编程实用工具。这个工具简单的说就为你的代码产生美观的缩进的格式。indent 也有很多选项来指定如何格式化你的源代码,这些选项的更多信息请看 indent 的指南页。indent 的简单用法是:indent 程序文件名。
以下使用vi编辑器编写一段C语言源码文件。

使用indent格式化代码

先cat查看格式化前的代码

再格式化并查看格式化后的代码

Linux 的编译器 gcc
C 语言是 Linux 下的最常用的程序设计语言,Linux 上的很多应用程序就是用 C 语言编写的。我们实验中的编程都是使用 C 或者 C++来实现的。Linux 系统上运行的 GNU C编译器(GCC)是一个全功能的ANSIC兼容编译器。虽然GCC 没有继承的开发环境,但堪称是目前效率很高的 C/C++编译器。
命令格式:gcc [选项] 源文件 [目标文件] ,选项含义:-o FILE 指定输出文件名,在编译为目标代码时,这一选项不是必须的。如果 FILE 没有指定,默认文件名是 a.out.-c GCC 仅把源代码编译为目标代码。默认是 GCC 建立的目标代码文件有一个.o 的扩展名。-static 链接静态库,即执行静态链接。-O GCC 对源代码进行基本优化。这些优化在大多数情况下都会使程序执行得更快。-On 指定代码优化的级别为 n,n 为 0≤n≤3 的正整数。-O2 选项告诉 GCC产生尽可能小和尽可能快的代码。-O2 选项使编译的速度比使用-O 时慢,但通常产生的代码执行速度会更快。-g 在可执行程序中包含标准调试信息。GCC 产生能被 GNU 调试器使用的调试信息,以便调试你的程序。GCC 提供了一个很多其他C编译器没有的特性,在 GCC 里可以把-g 和-O(产生优化代码)连用。-pedantic 允许发出 ANSI/ISO C 标准所列出的所有警告。-pedanic -errors 允许发出 ANSI/ISO C 标准所列出的所有错误。-w 关闭所有警告,建议不要使用此项。-Wall 允许发出 GCC 能提供的所有有用的警告,也可以用-W(warning)来标识指定的警告。-MM 输出一个 make 兼容的相关列表。-v 显示在编译过程中的每一步用到的命令。例 编译 hello.c 源文件: g c c h e l l o . c − o h e l l o 将 h e l l o . c p p 编 译 为 目 标 代 码 : gcc hello.c -o hello 将 hello.cpp 编译为目标代码: gcchello.cohellohello.cppgcc -c hello.cpp -o hello.o gcc 的主要选项选项 解释-ansi 只支持 ANSI 标准的 C 语法。这一选项将禁止GNU C 的某些特色, 例如 asm 或 typeof 关键词。-c 只编译并生成目标文件。-E 只运行 C 预编译器。-g 生成调试信息。GNU 调试器可利用该信息。-IDIRECTORY 指定额外的头文件搜索路径 DIRECTORY。-LDIRECTORY 指定额外的函数库搜索路径 DIRECTORY。-lLIBRARY 连接时搜索指定的函数库 LIBRARY。-m486 针对 486 进行代码优化。-o FILE 生成指定的输出文件。用在生成可执行文件时。-O0 不进行优化处理。-O 或 -O1 优化生成代码。-O2 进一步优化。-O3 比 -O2 更进一步优化,包括 inline 函数。-static 禁止使用共享连接。-UMACRO 取消对 MACRO 宏的定义。-w 不生成任何警告信息。-Wall 生成所有警告信息。
此时我们使用gcc编译刚刚写的源码,发现有bug,原因是我将C语言语法和Java语法搞混了,修正后编译正常。

实验四 线程管理实验
实验日期: 2022.4.28 报告分:
实验目的:
通过实际上机调试和运行程序了解 Linux 系统中的进程基本编程:创建和终止,了解父进程和子进程的概念。
预习报告:
进程(process 或 task)现在已经成为操作系统和并发程序设计中一个非常重要的概念。关于进程概念的讨论在操作系统中已经很详细。在 Linux 系统中,进程被认为是具有一定功能的程序关于一个数据集合的一次运行活动,是处于活动状态的计算机程序。进程在运行态、就绪态、等待态、stopped 和 zombie 这几种状态之间相互转化,但对用户是透明的。如果 Linux 系统中某个进程崩溃,不会影响到其它的进程。每个进程运行在各自的虚拟地址空间中,通过一定的通讯机制,它们之间才能发生联系。Linux 系统中的最大进程数目缺省值一般为 512,每个进程都有一个在系统中唯一的进程标识号(process Identifiers),系统就根据这些进程 ID 来管理进程。创建一个新进程的唯一方法是由某个已经存在的进程调用 fork 函数(或vfork 函数,本讲义不介绍),被创建的新进程是子进程,已经存在的进程是父进程。当然某些特殊进程并不需要通过这种方法来创建,如 swapper 进程、init 进程等,它们是作为操作系统启动的一部分而被内核创建的。
可以使用ps aux或者ps axj命令查看进程的状态。进程有很多的不同的状态,在kernel源代码中是这样定义的:
static const char * const task_state_array[] = {
“R (running)”, /* 0 /
“S (sleeping)”, /
1 /
“D (disk sleep)”, /
2 /
“T (stopped)”, /
4 /
“t (tracing stop)”, /
8 /
“X (dead)”, /
16 /
“Z (zombie)”, /
32 */
};
即运行态、就绪态、等待态、stopped 和 zombie 这几种状态。进程还拥有优先级,进程优先级为进程获取cpu资源分配的先后顺序,即进程的优先权,优先级高的进程可以有优先执行的权力。

实验观测记录及数据处理:
进程(process 或 task)现在已经成为操作系统和并发程序设计中一个非常重要的概念。关于进程概念的讨论在操作系统中已经很详细。在 Linux 系统中,进程被认为是具有一定功能的程序关于一个数据集合的一次运行活动,是处于活动状态的计算机程序。进程在运行态、就绪态、等待态、stopped 和 zombie 这几种状态之间相互转化,但对用户是透明的。如果 Linux 系统中某个进程崩溃,不会影响到其它的进程。每个进程运行在各自的虚拟地址空间中,通过一定的通讯机制,它们之间才能发生联系。Linux 系统中的最大进程数目缺省值一般为 512,每个进程都有一个在系统中唯一的进程标识号(process Identifiers),系统就根据这些进程 ID 来管理进程。创建一个新进程的唯一方法是由某个已经存在的进程调用 fork 函数(或vfork 函数,本讲义不介绍),被创建的新进程是子进程,已经存在的进程是父进程。当然某些特殊进程并不需要通过这种方法来创建,如 swapper 进程、init 进程等,它们是作为操作系统启动的一部分而被内核创建的。
使用老师提供的源码文件,执行gcc 文件名.c -o 文件名.o,编译成可执行文件。
函数 fork()是用来创建新进程的:pid_t fork(void); // 数据类型 pid_t 可认为就是 int 类型函数 fork()是一个单调用双返回的函数。具体的说,某个进程调用此函数后,若创建子进程成功,则这个函数在父进程中返回值是创建的子进程的进程标识号,而在子进程中返回值为零,否则(创建不成功)返回为-1。每个进程可以有多个子进程,但没有哪个函数调用是用来将子进程的进程标识号返回给父进程的;而每个进程至多有一个父进程,利用 getppid()函数可以得到父进程的进程标识号。回此 fork()函数将子进程的进程标识号返回给了父进程,便于父进程利用此进程标识号与子进程取得联系;而统一给子进程返回零。这个可以很简单地区分父进程和子进程。子进程是父进程的一个拷贝。具体地说,子进程从父进程那里得到了数据段和堆栈段的拷贝,这些需要分配新的内存,而不是与父进程共享内存。函数 fork()返回后,子进程和父进程一样都是从调用 fork()函数的语句的下一条开始执行。
调用./fork3.o函数,执行fork3.o文件,结果如图所示:

第一次调用fork()函数,创建父进程,之后创建生成一个子进程,之后父子进程交替进行,如果当前是父进程则显示parent子进程则显示child,再次执行几次,得到以下输出,可见每次调用所创建的进程都是全新的,与上次不同。

由于每次父子进程的执行是交替的,不可预知的,所以每一次执行的结果均不一样,但是由于程序规定,执行总数是一定的。如果再次运行此程序,系统分配给进程的 ID 一般会发生变化,两次运行的结果均是子进程先运行。一般来说,fork 之后是父进程先执行还是子进程先执行是不确定的,这取决于内核所使用的算法。将例 4-1 稍微修改一下就可以发现父进程和子进程是交替执行的,因为操作系统一般让所有的进程都享有同等执行权,除非某个进程的优先级比其它的高,下面对代码进行改进之后再进行测试。
使用fork或vfork创建子进程后,子进程通常会调用exec函数来执行另外一个程序。系统调用exec用于执行一个可执行程序以代替当前进程的执行映像。需要注意的是exec调用并没有生成新进程。一个进程一旦调用exec函数,它本身就“死亡了”,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段和堆栈段,唯一保留的就是进程的ID。也就是说,对系统而言,还是同一个进程,不过执行的已经是另外一个程序了。
下面先后执行processimage.o再执行exec.o,进行验证。
程序截图如下:
由此分析,在运行两段代码的的过程中,processimage.o从id为8912的进程创建一个id为8912的子进程,对于这个进程uid和gid都是1000,之后我们执行了exec.o,杀死了这个进程,可以发现pid和ppid都更新了,说明所执行的程序不是原先的了,但是uid和gid没变,说明对于计算机这还是一个进程。
当父进程先于子进程退出时,如果父进程没有调用wait和waitpid函数,子进程就会进入僵死状态。如果父进程调用了wait和waitpid函数,就不会使子进程变为僵尸进程,这两个函数声明如下:
#include<sys/types.h>
#include<sys/wait.h>
pid_t wait(int *statloc);
pid_t waitpid(pid_t pid, int *statloc, int options);
wait函数使父进程暂停执行,直到它的一个子进程结束为止。该函数的返回值是终止运行的子进程的PID。参数statloc所指向的变量存放子进程的退出码,即从子进程的main函数返回的值或子进程中exit函数的参数。如果statloc不是一个空指针,状态信息将被写入它指向的变量。检查wait和waitpid所返回的终止状态的宏。
waitpid也用来等待子进程的结束,但它用于等待某个特定进程结束。参数pid指明要等待子进程的PID。pid值的意义见下表。参数statloc的含义与wait函数中的statloc相同。options参数允许用户改变waitpid的行为,若将该参数赋值为WNOHANG,则使父进程不被挂起而立即返回并执行其后的代码。如果想让父进程周期性地检查某个特定的子进程是否已经退出,可以按如下方式调用waitpid。
waitpid(child_pid,(int *) 0,WNOHANG);
如果子进程尚未退出,它将返回0;如果子进程已经结束,则返回child_pid。调用失败时返回-1。失败的原因包括没有该子进程、参数不合法等。注意:wait等待第一个终止的子进程,而waitpid则可以指定等待特定的子进程。waitpid提供了一个wait的非阻塞版本。有时希望取得一个子进程的状态,但不想使父进程阻塞,waitpid提供了一个这样的选项:WNOHANG,它可使调用者不阻塞。如果一个没有任何子进程的进程调用wait函数,会立即出错返回。
以下我们运行wait.o进行验证,运行截图如下:
在这里里面,子进程休眠五次后结束,在这期间,父进程一直等待子进程结束,最后获取到子进程pid,打印输出,退出程序。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值