操作系统(02327)实践环节是操作系统专业课的上级测试部分,考核目标是具有熟练使用 Linux 系统常用命令的能力以及初步掌握进程的创建、控制及进程间通信程序的编写方法。运行环境是通过 putty 远程登录工具远程连接 Linux 服务器,在练习时我仍旧使用系统默认终端(zsh)连接云服务器使用。以下为我在学习和实战练习过程中所做的笔记,可供参考。
一、Linux 系统常用命令的使用
登陆命令
建立 SSH 连接:ssh root@zhuangzhihao.top
清屏:ctrl + l
或者 clear
终止当前运行:ctrl + c
执行 exit 命令退回到原来用户:exit
或 logout
或 ctrl + d
文件处理命令
显示当前目录下的文件:ls
显示当前目录下的所有文件,包括隐藏文件:ls -a
列表显示详细信息:ls -l
在此目录下创建一个 dir
目录:mkdir dir
递归创建,如果没有 dir
目录的话会报错,如果加上 -p
则不会:mkdir -p dir/subdir
同时创建 dir/subdir
、dir2
三个目录:mkdir -p dir/subdir dir2
切换路径到 root
目录下:cd /root
切换到上一目录:cd ./
切换到下一目录:cd ../
删除当前目录下,一个空白目录 dir
:rmdir ./dir
显示当前路径:pwd
将 install.sh
文件,复制到 dir
目录下:cp install.sh dir
将 dir
目录,复制到 dir2
目录下:cp -r dir dir2
将 dir
这个目录,复制到 dir2
目录下,如果没有 newdir
目录,那么将 dir
的名字改为 newdir
:cp -r dir dir2/newdir
将 install.sh
文件,复制到 dir2
目录下,但保证 install.sh
文件属性不会改变,例如最后一次修改的时间不会改变:cp -p install.sh dir2
将 dir
目录剪切到 dir2
目录:mv dir dir2
(如果没有 dir2
这个目录,呢么就是将 dir
的名字改为 dir2
,相当于改名。)
删除 install.sh
文件,出现提示是否删除确认:rm install.sh
删除 install.sh
文件,-f
不出现提示:rm -f install.sh
直接删除 dir
目录,-r
删除目录:rm -rf dir
直接删除此文件夹下的所有文件目录:rm -rf *
创建一个空文件 hello.c
:touch hello.c
同时创建 hello
和 hello.c
两个文件:touch hello hello.c
创建一个文件名为 hello hello.c
的文件:touch "hello hello.c"
显示 hello
文件内容:cat hello
显示 hello
文件内容,并显示行数:cat -n hello
倒着显示 hello
文件内容(没有 -n
属性):`tac hello
将 hello
文件的内容分页显示:more hello
(当数据较多时可以使用这命令,使用空格或 f
翻页,q
退出)
将 hello
文件的内容倒着显示分页显示:less hello
查看 hello
文件前 5 行内容:head -n 5 hello
(如果不加行数,默认为 10)
查看 hello
文件后 10 行内容:tail-n hello
链接文件
创建 hello
文件的软连接为 hello.sort
:ln hello ./hello.sort
创建 hello
文件的硬连接为 hello.sort
:ln -s hello ./hello.sort
创建 dir
目录的软连接为 dir.sort
:ln dir ./dir.sort
(注意:不允许将硬链接指向目录)
编译链接:gcc -otest.out E1_fork.c
(生成可执行文件 test.out
)
运行当前目录下的可执行文件 test.out
:./test.out
权限管理命令
改变目录或文件权限:chmod [设置权限的对象]+/-[权限] [文件]
- 设置权限的对象包括所有者、所属组、其他这三类。
u
表示文件的所有者,g
表示文件的所属组,o
代表其他人,+
代表增加权限,-
代表去掉权限 - 文件的权限就是读、写和执行,分别用
r
、w
、x
表示 - 多个设置权限可以使用逗号分隔:
chmod u+x,g+w abc.txt
将 abc.txt
文件所属组的权限增加一个写的权限:chmod g+w abc.txt
假设您是名为 myfile
的文件的所有者,并且要设置其权限,以便:user
可以 read
,write
和 execute
它,且你的 group
的成员可以 read
和 execute
它,且 others
只能读取它:
1 | chmod u=rwx,g=rx,o=r myfile |
使用八进制权限表示法的数字权限,4 代表阅读, 2 代表写, 1 代表执行,以及 0 表示无权限。
- 因此,7 是权限 4 + 2 + 1(读取、写入和执行),5 是 4 + 0 + 1(读取、无写入和执行),4 是 4 + 0 + 0(读取、无写入和未执行)。
- 数字表示权限,三个数字分别表示所有者,所属组和其他人。
- 给 user、group 和 others 都赋予读写执行权限:
chmod 777 abc.txt
修改 hello
.c 文件的所有者为 zhuang:chown zhuang hello.c
修改 hello
.c 文件的所属组为 xionggroup
:chgrp xionggroup hello.c
显示,设置文件的缺省权限:umask -S
文件搜索命令
在当前目录下搜索名字为 myfile
的文件,区分大小写:find ./ -name myfile
在当前目录下搜索名字为 myfile
的文件,不区分大小写:find ./ -i name myfile
在当前目录下搜索名字以 .c
结尾的文件,区分大小写:find ./ -name "*.c"
在当前目录下搜索名字包含 ello
的文件,区分大小写:find ./ -name "*ello*"
在当前目录下搜索名字包含 bb
的目录,区分大小写:find ./ -name "*bb*" -type d
(d
:目录, f
:文件, i
:软链接)
在文件资料库查找文件 myfile
,区分大小写:locate myfile
查询 Linux 系统中命令的位置以及被查询命令帮助文档的位置:whereis cp
查找一个存储所有命令相关信息的数据库,根据命令名返回相关结果:whatis cp
过滤 test.txt
文件中 hello
内容:grep hello test.txt
(加 -i
不区分大小写)
统计 test.txt
中 hello
内容的行数:grep -c hello test.txt
帮助命令
获得 shell
内置命令 date
的帮助信息:help date
获得帮助信息,比命令的 help 选项多了命令的用法示例、命令的描述等内容:man date
用户管理命令
增加一个 zhuang
用户:useradd zhuang
修改 zhuang
用户的密码:passwd zhuang
切换用户为 zhuang
:su zhuang
显示目前登入系统的用户信息:who
或者 w
压缩解压命令
将 myfile
文件压缩为 myfile.gz
:gzip myfile
(只能压缩文件,原文件不保留)
解压 myfile.gz
文件:gunzip myfile.gz
将目录 dir
直接打包并压缩为 name.tar.gz
打包目录:tar -zcf name.tar.gz dir
(.tar.gz)
将 name.tar.gz
打包目录解压:tar -zxf name.tar.gz
(-x
:解包,-c
:打包,-v
:显示详细信息,-f
:指定文件名,-z
:同时打包压缩)
将目录 dir
压缩为 name.zip
:zip -r name dir
将 name.zip
解压:unzip name.zip
网络命令
给用户 zhuang
发送信息(开启聊天框),按 ctrl+d
结束:write zhuang
给所有在线用户发送广播 helloworld
:wall helloworld
查看网卡和设置信息:ping
查看网卡和设置网卡信息:ifconfig
列出过去和现在登入系统的用户信息:last
列出特定用户上次登录时间:lastlog
关机重启命令
重启:reboot
立刻关机:halt
或 poweroff
立刻重启(root 用户使用):shutdown -r now
(-c:取消前一个关机命令,-h :关机,-r :重启)
过10分钟自动重启(root用户使用):shutdown -r 10
过10分钟自动关机(root用户使用):shutdown -h 10
在时间为 21:00 时候重启(root用户使用):shutdown -r 21:00
如果是通过 shutdown
命令设置重启或关机的话,可以用 shutdown -c
命令取消重启。
退出登录命令:logout
二、进程的创建、控制及进程间通信
getpid() 获取 PID
getpid
获取当前进程 ID,getppid
获取父进程 ID。
pid_t
是 C 语言中用户自定义类型,在 sys/types.h
中定义,typedef int pid_t;
1 |
|
打印当前进程的 PID:
1 |
|
fork() 创建进程
fork
创建一个子进程,父子进程并发运行,子进程复制父进程的如下属性:
- 代码段、数据段的内容,父子进程拥有相同的代码和数据。
- 打开文件列表。
fork
不复制进程的 PID 属性,父子的进程的 PID 都是唯一的。
返回值:
pid
是进程 ID 的缩写,pid_t
是使用typedef
定义的进程 ID 类型。- 父进程从
fork
返回处继续执行,在父进程中,fork
返回子进程 PID。 - 子进程从
fork
返回处开始执行,在子进程中,fork
返回 0。
1 |
|
创建子进程:
1 | int main() |
fork()
进程有以下几个特点:
- 调用 1 次,返回 2 次。 一次是在父进程中执行,一次是在刚创建的子进程中执行。 pid 为 0,表示当前在子进程中。
- 并发执行。 父进程和子进程是并发运行的独立进程。 内核以任意方式交替执行,可能会先执行父进程,也可能会先执行子进程。 程序员应该避免猜测谁先执行来做一下逻辑处理。
- 拥有相同且独立的地址空间:刚 fork 出的子进程和父进程拥有相同的用户栈、堆,变量。但他们相互独立的。 例如例子中:输出 x 的变量值,child 自增 1 与 parent 自减 1 互不影响。
其他进程控制相关函数
wait()
:查询子进程的退出状态(即正常退出的退出码或导致异常终止的信号),并回收子进程的内核资源。若成功则返回进程 ID,若出错则返回 -1。
1 |
|
wait()
函数常用来控制父进程和子进程的同步。在父进程中调用 wait()
函数,则父进程被阻塞,进入等待队列,等待子进程结束。当子进程结束时,会产生一个终止状态字,系统会向父进程发送 SIGCHLD 信号。当接到信号后,父进程提取子进程的终止状态字,从 wait()
函数返回继续执行原程序。
exit()
:进程结束最常调用的函数,在 main()
函数中调用 return
,最终也是调用 exit()
函数。这些都是进程的正常终止。在正常终止时,exit()
函数返回进程结束状态。
1 |
|
从 OS 角度来看,进程终止会释放进程用户空间的所有资源,而进程描述符并不释放,它将来由其父进程回收。若父进程先于子进程终止,子进程成为孤儿进程,孤儿进程会被 init
进程(进程号为1)领养。若子进程先于父进程终止,子进程成为僵尸进程,父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占用的资源)。
程序可以执行到 main()
的最后一个 }
的结束,也可以运行 exit();
结束,也可以运行到 return 0;
结束。
execl()
:系统调用 execl()
可以将新程序加载到某一进程的内存空间,该进程会从新程序的 main()
函数开始执行。
1 |
|
进程的用户内存空间被替换,而进程的其他属性基本不改变。进程完整的内存空间:正文区、堆区、栈区、数据区都被替换,原内容不存在了。代码替换完后,在 execl()
后面的代码毫无意义。
创建多个进程:
1 | //print1.c |
1 | //multi_process.c |
运行:
1 | gcc print1.c –o print1 |
进程间通信(IPC)
注意:在超级用户(管理员)下才可以进行共享内存进程通信,否则提示段错误。使用 su -
切换。
共享内存实现 IPC 基本步骤:
- 获得唯一的
key
值:一般采用ftok
得到唯一的键值, - 使用
shmget
创建或获得共享内存区, - 使用
shmat
将共享内存区附加到进程中, - 使用共享内存区,
- 与共享内存区脱离,但是记住这时共享内在区,依然存在,必须等到内核重启,
- 申请的共享内存区的大小是有限制的。
实验内容:应用 Linux 共享内存机制,实现两个进程间相互传递一个学生的记录,包括:
- 学号:SID,char 型,8 位
- 姓名:NAME,char 型,8 位
- 年龄:Age,int 型
- 专业:Specialty,char 型,8 位
- 班级:Class,char 型,4 位一个记录约 30 个字节。
共享内存函数由 shmget
、shmat
、shmdt
、shmctl
四个函数组成:
1 | //shm1 |
1 | //shm2 |