第一讲 操作系统概述

第五节 实践:试试UNIX/Linux

向勇 陈渝 李国良 任炬

2024年春季


UNIX/Linux?

  • Linux
    • Ubuntu、Fedora、SuSE、openEuler
    • 麒麟 统信
  • Windows with WSL (Windows Subsystem of Linux)
  • MacOS with UNIX shell

bg right 90%


UNIX/Linux?

  • 开放源码,有很好的文档,设计简洁,使用广泛
  • 如果你了解Linux的内部情况,学习ucore/rcore会有帮助。

bg right 100%


Try UNIX/Linux

  • shell

    • bash 基本的shell环境
    • fish 强调交互性和可用性
    • zsh 带有自动补全、支持插件
    • starship 轻量、迅速、可无限定制
  • program

    • ls, rm,gcc,gdb, vim ...

bg right:40% 100%


UNIX/Linux提供哪些服务?

  • 进程(正在运行的程序)
  • 内存分配
  • 文件内容、文件名、目录
  • 访问控制(安全)
  • 许多其他的:用户、IPC、网络、时间

bg right 100%


UNIX/Linux提供的应用/内核接口?

  • APP -> C lib -> Syscall -> Kernel

  • 用C语言,来自类UNIX OS

          fd = open("out", 1);
          write(fd, "hello\n", 6);
    
  • 看起来像函数调用,其实是系统调用

  • 核心的系统调用数量并不多

bg right:50% 100%


UNIX/Linux提供的应用/内核接口?

系统调用名含义
int fork()创建一个进程,返回子进程的PID。
int exit(int status)终止当前进程;报告状态给执行wait()系统调用的父进程。没有返回。
int wait(int *status)等待子进程退出;退出状态为 *status ;返回子进程的PID。
int kill (int pid)终止进程号为PID的进程。返回0表示成功,或-1表示错误。
int getpid()返回当前进程的PID。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int sleep(int n)暂停n个时钟周期。
int exec(char *file,char *argv[])用参数加载文件并执行;仅当出错时返回。
char *sbrk(int n)将进程内存增加n个字节。返回新内存的开始地址。
int open(char *file,int flags)打开文件;标志flag表示文件操作的读/写属性;返回一个fd(文件描述符)。
int write(int fd,char *buf,int n)从buf向文件描述符fd写入n个字节;返回n。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int read(int fd,char *buf,int n)将n个字节读入buf;返回读取的数字;如果文件结束,则为0。
int close(int fd)释放打开的描述符为fd的文件。
int dup(int fd)返回一个新的文件描述符,引用与文件描述符相同的文件。
int pipe(int p[])创建一个管道,将读/写文件描述符放在p[0]和p[1]中。
int chdir(char *dir)更改当前目录。

UNIX/Linux提供的应用/内核接口?

系统调用名含义
int mkdir(char *dir)创建一个新目录。
int mknod(char *file, int, int)创建一个设备文件。
int fstat(int fd,struct stat *st)将文件fd的元信息放入*st
int stat(char *file,struct stat *st)将文件 *file 的元信息放入 *st
int link(char *file1,char *file2)为文件file1创建另一个名称(file2)
int unlink(char *file)删除文件。

UNIX/Linux应用

分析一些非常简单的小程序

进程相关

fork.c exec.c forkexec.c

文件系统相关

list.c open.c echo.c copy.c

进程间通信相关

pipe1.c pipe2.c redirect.c

bg right:55% 100%


UNIX/Linux应用 - open

  • 例如:open.c,创建一个文件

    $ open $ cat output.txt

  • open() 创建一个文件,返回一个文件描述符(File Descriptor,简称FD,或-1表示错误)。

  • FD是正整数,代表一个打开的文件

  • 进一步细节可以参考UNIX/Linux手册,例如执行 "man 2 open"

  • man的第一个参数:1 表示查shell命令;2 表示查系统调用


UNIX/Linux应用 - copy

例如:copy.c,将输入文件内容复制到输出文件中 从输入文件中读取字节内容,将其写入输出文件中

    copy

read()和write()是系统调用 read()/write()第一个参数是"文件描述符"(fd) 传递给内核,告诉它要读/写哪个 "打开的文件"


UNIX/Linux应用 - copy

  • 一个文件描述符对应一个打开的文件

  • 一个进程可以打开许多文件,有许多描述符

  • 缺省情况:

    • 文件描述符0是 "标准输入", 通常是键盘
    • 文件描述符1是 "标准输出",通常是显示器
  • read()第二个参数是指向要读取的缓冲区的指针,缓冲区的大小由第三个参数指定

  • 文件访问模式:open -> read/write -> close


UNIX/Linux应用 - fork

fork()系统调用创建一个进程的副本(子进程)

  • 复制:指令、数据、寄存器、文件描述符、当前目录
  • 形成"父 "和 "子 "进程

bg right:50% 100%


UNIX/Linux应用 - fork

  • 区别:fork()在父进程中返回一个pid,在子进程中返回0。

  • pid(进程ID)是一个整数,内核给每个进程一个不同的pid

  • 因此,fork.c中父子进程的fork()返回值pid不同

  • 父子进程的执行差别就体现在对fork()返回值pid的判别上

    • 0代表子进程,否则代表父进程

bg right:40% 100%


UNIX/Linux应用 - exec

  • 怎样才能在这个进程中运行一个新程序呢?

  • 例如:exec.c,用一个可执行文件代替调用进程。

exec(filename, argument-array) argument-array保存命令行参数;exec传递给main()

exec()用新执行文件取代当前进程

  • 丢弃已有指令和数据内存空间
  • 从文件中加载新执行程序的指令和数据

UNIX/Linux应用 - forkexec

例如:forkexec.c,fork()一个新进程,exec()一个程序。

常见的UNIX APP执行模式

  • fork():创建子进程
  • exec():子进程中执行新程序
  • wait():父进程等待子进程完成
  • exit():进程退出

bg right:45% 100%


UNIX/Linux应用 - redirect

例子:redirect.c,重定向一个命令的输出

  • 缺省情况下,文件描述符为1的文件是屏幕输出
  • open()总是选择值最小的未使用的文件描述符
  • 通过 close(1) + open(...)操作,设定"output.txt"的文件描述符为1
  • exec(...)系统调用保留了文件描述符,执行echo命令后,它的屏幕输出将被重定向到"output.txt"
    redirect
    cat output.txt

分析UNIX/Linux类应用 - pipe2

  • 例子pipe2.c,进程间通信。
  • shell如何使用管道机制 "|"
    ls | grep x

pipe()系统调用创建了两个fd

  • 从fd[1]写入,从fd[0]中读取

bg right:50% 100%


UNIX/Linux应用

一些值得思考的问题:

  • 为什么是这些I/O和进程的抽象?为什么不是其他的东西?
  • 为什么要提供一个文件系统,而不让程序以自己的方式使用磁盘?
  • 为什么read/write文件用FD而不是文件名?
  • 为什么文件是字节流,而不是磁盘块或格式化记录?
  • 为什么不把fork()和exec()结合起来?

UNIX的设计很好用,但也存在其他的设计


分析UNIX/Linux类应用

小结

  • 介绍了UNIX的I/O、文件系统和进程的抽象
  • 这些接口很简洁,只有整数和I/O缓冲区
  • 这些抽象结合得很好,例如,I/O重定向

【总结笔记】

本节介绍了UNIX/Linux系统的基础,提供一个初步的操作实践指南。通过本节内容,学生将了解UNIX/Linux系统的基本概念、如何在不同环境中尝试使用UNIX/Linux,以及UNIX/Linux系统提供的核心服务和应用程序接口。

UNIX/Linux基本介绍

UNIX和Linux代表了一系列基于开放源代码的操作系统,它们以其稳定性、灵活性和强大的网络功能著称。Linux拥有多个发行版,如Ubuntu、Fedora、SuSE、openEuler、麒麟和统信,每个都有其特点和目标用户。此外,Windows用户可以通过Windows Subsystem for Linux (WSL) 在Windows环境中运行Linux,而MacOS用户则可以通过内置的UNIX shell来体验UNIX环境。

尝试UNIX/Linux

Shell环境

  • bash: UNIX和Linux系统中最基本的shell。
  • fish: 以用户交互性和易用性为特点的现代shell。
  • zsh: 提供自动补全功能和丰富的插件支持的强大shell。
  • starship: 一个轻量、快速且高度可定制的shell提示符。

常用程序

  • 基础命令行工具如ls(列出目录内容)、rm(删除文件或目录)、gcc(GNU编译器集合)、gdb(GNU调试器)、vim(文本编辑器)等,是日常操作中不可或缺的工具。

UNIX/Linux提供的服务

UNIX/Linux系统提供的服务覆盖了进程管理、内存分配、文件系统操作、访问控制以及网络和时间管理等方面。这些服务是通过系统调用(Syscall)来实现的,系统调用为用户空间的应用程序提供了访问操作系统内核功能的方式。

应用/内核接口

UNIX/Linux系统的应用程序通过C库(C lib)调用系统调用接口(Syscall)与内核(Kernel)进行交云。例如,使用open系统调用打开文件,write系统调用写入内容。这些看起来像普通函数调用的接口实际上触发了内核级的操作,使得应用程序能够执行诸如创建进程、读写文件等操作。

UNIX/Linux应用示例

通过分析和运行一些基本的UNIX/Linux应用程序,如fork.cexec.copen.ccopy.c等,学生可以深入理解UNIX/Linux系统调用的使用方式和程序之间的交云方式。这些示例程序涵盖了进程管理、文件操作和进程间通信等多个重要概念。