guanjinquan 1 سال پیش
والد
کامیت
85bb27cbb4
6فایلهای تغییر یافته به همراه1086 افزوده شده و 0 حذف شده
  1. BIN
      docs/.vuepress/public/process.png
  2. BIN
      docs/.vuepress/public/tree.png
  3. 131 0
      docs/Assignment/Lab1.md
  4. 59 0
      docs/Assignment/Lab2.md
  5. 527 0
      docs/Lab/Lab1.md
  6. 369 0
      docs/Lab/Lab2.md

BIN
docs/.vuepress/public/process.png


BIN
docs/.vuepress/public/tree.png


+ 131 - 0
docs/Assignment/Lab1.md

@@ -0,0 +1,131 @@
+---
+sidebar: auto
+---
+
+# Lab-1 熟悉类Linux系统的命令
+
+## 本节导读
+
+通过练习掌握Linux一般命令格式,掌握有关文件和目录操作的常用命令,学会使用vi编辑器建立、编辑、显示及加工处理文本文件。
+
+## 实验内容
+
+### 简单命令的使用
+
+使用以下命令,看看系统会输出什么:
+
+`date`命令:显示或设置系统的日期或时间
+
+`cal`命令:显示公元1-9999年中任意一年或任意一个月的日历
+
+`who`命令:列出所有正在使用系统的用户、所有终端名和注册到系统的时间
+
+`clear`命令:清除屏幕上的信息
+
+如果你忘了命令对应的功能或如何使用它们,请尝试使用`man`和`help`命令寻求帮助
+
+### 浏览文件系统
+
+1. 运行`pwd`命令,查看当前工作目录
+
+2. 运行`ls -l`命令,尝试理解输出各字段的含义
+
+3. 运行`ls -ai`命令,看看发生了什么变化,尝试理解输出各字段的含义
+
+4. 使用cd命令,将工作目录更改到根目录上
+
+```shell
+$ cd /
+```
+
+再次运行`ls -l`命令,查看该目录下有哪些东西,了解各目录的作用
+
+5. 这时如果直接使用`cd`命令,当前路径是什么?尝试使用相应命令查看并验证
+
+6. 使用mkdir建立一个子目录subdir
+
+```shell
+$ mkdir subdir
+```
+
+7. 子目录创建成功了吗?让我们使用`ls`命令查看,并将工作目录更改到subdir
+
+```shell
+$ ls
+$ cd subdir
+```
+
+### 对文件和目录操作
+
+1. 运行date > file1,然后运行cat file1,我们将看到什么信息?
+
+```shell
+$ date > file1
+$ cat file1
+```
+
+2. 尝试运行`cat subdir`,会有什么结果?如果回到上一个目录,再次运行,又会有什么结果?为什么?
+
+```shell
+$ cat subdir
+$ cd ../
+```
+
+3. 运行`man date >>file1`,我们能看到什么?再运行cat file1,又看到什么?
+
+```shell
+$ man date >>file1
+$ cat file1
+```
+
+4. 利用`ls -l file1`,该文件链接计数是多少?运行`ln file1 ../fa`,再运行`ls -l file1`,看链接计数有无变化?
+
+```shell
+$ ls -l file1
+$ ln file1 ../fa
+```
+
+5. 用cat命令显示fa文件内容,注意fa文件所在位置,理解`ln`命令的作用是什么。
+
+6. 尝试显示file1的前10行,后10行。
+
+```shell
+# 尝试使用多种方法
+$ head -10 file1
+$ cat file1 | tail -n 10
+```
+
+7. 运行`cp file1 file2`,然后`ls -l`,会看到什么?运行`mv file2 file3`,然后`ls -l`,又看到什么?运行`cat f*`,结果如何?
+
+```shell
+$ cp file1 file2
+$ mv file2 file3
+$ cat f*
+```
+
+8. 运行`rm file3`,然后`ls -l`,结果如何?
+
+```shell
+$ rm file3
+$ ls –l
+```
+
+### vi编辑器的使用
+
+1. 建立一个文件,如file.c。输入一个C语言程序的各行内容,故意制造几处错误。
+
+>这里有多种方式,你可以通过`touch 文件名`来建立空白文件,接着在对应文件夹下使用`vi 文件名`进行操作
+>
+>或者,直接通过打开vi编辑器,进入插入模式,最后将该文件存盘。
+
+2. 运行`gcc file.c -o myfile`,编译该文件,会看到什么?尝试理解其含义。
+
+```shell
+$ gcc file.c -o myfile
+```
+
+3. 重新进入vi,对该文件进行修改。然后存盘,退出vi。重新编译该文件。如果编译通过了,可以用`./myfile`运行该程序。
+
+>`./`(点斜杠)的意思是执行当前目录下的某个可执行文件
+
+4. 运行`man date > file2`,然后`vi file2`。使用`x`,`dd`等命令删除某些文本行。使用`u`命令复原此前的情况。

+ 59 - 0
docs/Assignment/Lab2.md

@@ -0,0 +1,59 @@
+---
+sidebar: auto
+---
+
+# 进程创建与进程间通信
+
+## 本章导读
+
+通过练习理解进程创建以及进程并发执行的过程,握fork系统调用的方法,了解进程间通信的常用方法。
+
+## 实验内容
+
+### 进程创建
+
+请问在下方的代码中,一共有多少个进程被创建?
+
+>可以通过fork返回的值来判断当前进程是子进程还是父进程。
+
+```c
+#include <unistd.h>
+#include <stdio.h>
+ 
+int main()
+{
+    fork();
+    fork() && fork() || fork();
+    fork();
+    sleep(100);
+    return 0;
+}
+```
+
+### 创建进程树
+
+编写程序创建进程树如图所示,在每个进程中显示当前进程标识getpid()和父进程标识getppid()。
+
+![图片1](../.vuepress/public/tree.png '进程树')
+
+### 信号通信
+
+用fork()创建两个子进程,再用系统调用signal()让父进程捕捉键盘上来的中断信号(即DEL键);当捕捉到中断信号后,父进程用系统调用kill()向两个子进程发出信号,子进程捕捉到信号后分别输出下列信息后终止:
+
+Child process1 is killed by parent!
+
+Child process2 is killed by parent!
+
+父进程等待两个子进程终止后,输出如下的信息后终止:
+
+Parent process is killed!
+
+### 管道通信
+
+实现进程的管道通信,用系统调用pipe()建立一管道,二个子进程P1和P2分别向管道各写一句话:
+
+Child 1 is sending a message!
+
+Child 2 is sending a message!
+
+父进程从管道中读出二个来自子进程的信息并显示。

+ 527 - 0
docs/Lab/Lab1.md

@@ -1,2 +1,529 @@
+---
+sidebar: auto
+---
+
 # Lab-1 熟悉类Linux系统的命令
 
+## 本章导读
+
+本章意在介绍Linux系统的常用命令,要求掌握Linux一般命令格式,学会使用man命令来寻求帮助,学习使用命令对有关文件和目录进行操作,利用vi编辑器建立、编辑、显示及加工处理文本文件。
+
+## 帮助命令
+
+### `man`命令:显示联机帮助手册
+
+Linux的命令有很多参数,我们不可能全记住,我们可以通过man命令查看联机手册获取帮助。
+格式:man 命令
+
+```shell
+# 显示出ls命令的功能及选项的含义
+man ls
+```
+
+### `help`命令:显示帮助信息
+
+同时,也可以使用`help`命令查看帮助信息.
+
+```shell
+# 显示出ls命令的功能及选项的含义
+help ls
+```
+
+## 简单命令
+
+### `date`命令:显示时间
+
+显示或设置系统的日期或时间
+
+### `cal`命令:显示日历
+
+显示公元1-9999年中任意一年或任意一个月的日历
+
+### `who`命令:显示用户信息
+
+列出所有正在使用系统的用户、所有终端名和注册到系统的时间
+
+### `clear`命令:清除信息
+
+清除屏幕上的信息
+
+## 文件与目录的操作
+
+对文件可以进行的操作有:复制一个文件、显示文件内容、查找指定内容、排序、文件比较、文件删除等
+
+### `pwd`命令:显示绝对路径
+
+>**基本语法**
+
+```shell
+# 查看当前路径
+pwd
+```
+
+### `ls`命令:显示所有的文件和目录
+
+如果未指定目录则默认显示当前目录先的所有文件和目录
+
+>基本语法:*ls 目录或文件*
+
+```shell
+# 查看当前路径下所有文件或目录
+ls
+# 查看当前路径下所有文件或目录的详细信息
+ls -l
+# 查看当前路径下的隐藏文件
+ls -ai
+```
+
+### `cd`命令:切换目录
+
+>基本语法:*cd 目录*
+
+```shell
+# 切换到 /home 目录下
+cd /a
+# 切换到用户主目录
+cd ~
+# 切换到上一次访问的目录
+cd -
+# 切换到当前目录的上一级
+cd ..
+```
+
+### `mkdir`命令:创建目录
+
+>基本语法:*mkdir 目录名*
+
+```shell
+# 创建一个 dir 目录(一级)
+mkdir dir1
+# 创建 dir1 目录,其下再创建 dir2 目录(多级)
+# -p 选项用于创建多级目录
+mkdir -p dir1/dir2
+```
+
+### `rmdir`命令:删除目录(空目录)
+
+>基本语法:*rmdir 目录名*
+
+```shell
+# 删除 home 下的dir目录
+rmdir /home/dir
+```
+
+>>mdir 删除的是空目录,目录下有内容时是无法删除的,-rf 则可删除非空目录
+
+```shell
+# 强制删除 home 下的 dir 目录
+rmdir -rf /home/dir
+```
+
+### `touch`命令:创建空文件
+
+>基本语法:*touch 文件名*
+
+```shell
+# 创建 hello.txt 空文件
+touch hello.txt
+```
+
+### `cp`命令:拷贝文件或目录
+
+>基本语法:*cp 源文件 目标文件*
+
+```shell
+# 拷贝 hello.txt 文件到 /tmp/files 目录中
+cp file.txt /tmp/files
+# 递归将 home 下的整个 dir1 目录拷贝到 dir2 目录下
+cp -r /home/dir1 /dir2/
+# 如果连续执行相同的拷贝命令系统会一个一个提示是否覆盖文件内的文件
+# 这时在 cp 前加一个 \ 就可以进行强制覆盖,不提示
+\cp -r /home/dir1 /dir2/ 
+```
+
+### `rm`命令:删除文件或目录
+
+>基本语法:*rm 文件或目录*
+
+```shell
+# 删除指定的文件 file1.txt
+rm file.txt
+# 删除当前目录下的所有文件
+rm *
+# -r 递归删除 dir1 目录下的所有文件及子目录
+rm –r dir1
+# -f 强制删除文件,不提示
+rm –f file.txt
+```
+
+### `mv`命令:移动或重命名
+
+>基本语法:*mv 旧文件名 新文件名、mv /源目录 /目标目录*
+
+```shell
+# 将 file.txt 文件移到上层目录
+mv file.txt ..
+# 将 file1.txt 改名成 file2.txt
+mv file1.txt file2.txt
+```
+
+>>重命名的前提是两个文件在同一个目录下
+
+### `more`命令:文本过滤器
+
+>基本语法:*more 要查看的文件*
+
+```shell
+# 查看 file.txt 文件的内容
+more file.txt
+```
+
+>>more 指令是一个基于 vim 编辑器的文本过滤器(在后面我们我谈到vim编辑器)
+>>
+>>可以以全屏幕的方式按页显示文本文件的内容,且有若干快捷键:
+>>
+>>`space`向下翻一页
+>>
+>>`Enter`向下翻一行
+>>
+>>`q`立即离开more,不再显示文件内容
+>>
+>>`Ctrl+F`向下滚动以一屏
+>>
+>>`Ctrl+B`返回上一屏
+>>
+>>`=`输出当前行的行号
+>>
+>>`:f`输出文件名和当前行的行号
+
+
+### `cat`命令:查看文件内容或连接文件
+
+>基本语法:*cat 文件*
+
+### `> / >>`命令:输出重定向/追加
+
+>重定向 > 会覆盖之前内容,追加 >> 会将新内容添加到之前内容的末尾
+
+```shell
+# 和 more 命令搭配使用,逐页显示
+cat file.txt more
+# 将 file2.txt 附加到 file1.txt 文件之后
+cat file2.txt >> file1.txt
+# 将 file1.txt 和 file2.txt 合并成 file3.txt 文件
+cat file1.txt file2.txt > file3.txt
+```
+
+### `echo`命令:输出内容到控制台
+
+>基本语法:*echo 输出内容*
+
+```shell
+# 输出环境变量 $PATH
+echo $PATH
+# 输出语句“Hello World”
+echo "Hello World"
+```
+
+### `head`命令:显示文件开头部分
+
+>基本语法:*head 文件*
+>>默认情况下 head 显示文件的前十行
+
+```shell
+# 查看 file.txt 文件的前 10 行内容
+head file.txt
+# 查看 file.txt 文件的前 5 行内容
+head -n 5 file.txt
+```
+
+### `tail`命令:显示文件尾部的部分
+
+>基本语法:*tail 文件*
+>>默认情况下 tail 显示文件的后十行
+
+```shell
+# 查看 file.txt 文件的后 10 行内容
+tail file.txt
+# 查看 file.txt 文件的后 5 行内容
+tail -n 5 file.txt
+# 查看 file.txt 文件的后 10 行内容,并实时追踪文件更新
+tail -f file.txt 
+```
+
+### `ln命令`:在文件间建立链接
+
+>基本语法:*ln [选项] 源文件 目录文件或目录*
+>>选项说明:
+>>
+>>`-b`为删除的文件建立备份
+>>
+>>`-d`允许root用户建立硬链接
+>>
+>>`-F`与b相同
+>>
+>>`-f`强行删除目标文件
+>>
+>>`-i`在删除文件时给出提示
+>>
+>>`-n`当目标文件是目录的符号链接时,替代该符号链接
+>>
+>>`-s`用符号链接代替硬链接(建立符号链接)
+>>
+>>`-v`输出被链接文件的文件名
+>>
+>>>软链接也称符号链接,类似 Windows 中的快捷方式
+>>>
+>>>主要存放了链接其他文件的路径,删除软连接的方式与删除文件相同
+
+```shell
+# 创建一个软连接 myroot,连接到 /root 目录
+ln -s /root /myroot
+# 删除软连接 myroot
+rm /myroot
+```
+
+### `chmod`命令:修改文件权限
+
+>基本语法:*chmod [选项] 文件或目录名*
+>>选项说明:
+>>
+>>`u` 文件所有者
+>>
+>>`g` 文件所属组
+>>
+>>`o` 其它用户
+>>
+>>`a` 所有用户
+>>
+>>`+` 增加权限
+>>
+>>`-` 取消权限
+>>
+>>`=` 赋给权限
+>>
+>>`r` 读权限
+>>
+>>`w` 写权限
+>>
+>>`x` 执行权限
+
+```shell
+# 将 file1.txt 文件设为所有人皆可读写
+chmod a+rw file1
+# 将 file.py 设定为只有该档案拥有者可以执行
+chmod u+x file.py 
+```
+
+### `gcc`命令:编译
+
+>基本语法:*gcc [选项] 文件名*
+>>常用选项:
+>>
+>>`-v` 查看gcc编译器的版本,显示gcc执行时的详细过程
+>>
+>>`-o` 指定输出文件名为file,这个名称不能跟源文件名同名
+>>
+>>`-E` 只预处理,不会编译、汇编、链接
+>>
+>>`-S` 只编译,不会汇编、链接
+>>
+>>`-c` 编译和汇编,不会链接
+
+```shell
+# 编译 hello.c 并指定输出文件为 hello
+gcc hello.c -o hello
+```
+
+## 搜索查找类命令
+
+### `find`命令:查找文件
+
+>基本语法:*find 范围 方式 文件*
+
+```shell
+# 根据文件名查找 home 下的 file.txt 文件
+find /home -name file.txt
+# 根据用户查找 home 下用户昵称为 DrangonOS 的文件
+find /home -user DrangonOS
+# 根据文件大小查找系统中大小为 200M 的文件
+find / -size 200M
+```
+
+### `locate`命令:定位文件路径
+
+>基本语法:*locate 文件*
+>>locate 指令可以快速定位文件路径,利用事先建立的系统中所有文件名称及路径的 locate 数据库实现快速定位文件,无需遍历整个文件系统
+>>
+>>但为了保证查询准确度,管理员须定期更新locate时刻
+
+```shell
+# 创建 locate 数据库,第一次使用 locate指令前必须先创建数据库
+updatedb
+# 定位 file.txt 文件的路径
+locate file.txt
+```
+
+### `which`命令:定位指令路径
+
+>基本语法:*which 指令*
+
+```shell
+# 检索 cp 指令所在路径
+which cp
+# 输出
+alias cp='cp -i'
+    /usr/bin/cp
+```
+
+### `grep`命令:过滤查找(搜索字符串)
+
+>基本语法:*grep 查找内容 源文件*
+>>grep 命令可以搜索特定字符串来并显示出来,一般用来过滤先前得结果,避免显示太多不必要得信息
+
+```shell
+# 查找 hello.txt 文件中 “yes” 所在行
+grep "yes" hello.txt
+# 查找 hello.txt 文件中 “yes” 所在行
+cat hello.txt | grep "yes"
+#  查找 hello.txt 文件中 “yes” 所在行并显示行号
+cat hello.txt | grep -n "yes"
+```
+
+>>>`|`管道命令:将某命令的结果输出给另一命令
+
+## 压缩解压类命令
+
+### `tar`命令:打包文件
+
+>基本语法:*tar [选项] 内容*
+>>选项说明:
+>>
+>>`-c`创建一个新的tar文件
+>>
+>>`-v`显示运作过程信息
+>>
+>>`-f`指定文件名称
+>>
+>>`-z`调用gzip压缩命令执行压缩;
+>>
+>>`-j`调用bzip2压缩命令执行压缩
+>>
+>>`-t`查看压缩文件内容
+>>
+>>`-x`解开tar文件
+
+```shell
+# 将 file.tar.gz 解压到当前目录
+tar -zxvf a.tar.gz
+# 将 /home 下的文件夹压缩为 file.tar.gz
+tar -zcvf file.tar.gz /home/
+# 将 file.tar.gz 解压到 /tmp 目录下
+tar -zxvf file.tar.gz -c /tmp
+```
+
+>>>tar 打包后的文件为 .tar.gz 文件
+
+### `gzip`命令:压缩和解压缩文件
+
+>基本语法:*gzip [选项] 文件*
+>>选项说明:
+>>
+>>`-c`将输出写到标准输出上,并保留原有文件。
+>>
+>>`-d`将压缩文件解压。
+>>
+>>`-l`对每个压缩文件,显示下列字段:压缩文件的大小、未压缩文件的大小、压缩比、未压缩文件的名字
+>>
+>>`-r`递归式地查找指定目录并压缩其中的所有文件或者是解压缩。
+>>
+>>`-t`测试,检查压缩文件是否完整。
+>>
+>>`-v`对每一个压缩和解压的文件,显示文件名和压缩比。
+>>
+>>`-num`用指定的数字num调整压缩的速度,-1或--fast表示最快压缩方法(低压缩比),-9或--best表示最慢压缩方法(高压缩比),系统缺省值为6
+
+```shell
+# 将usr.tar压缩为usr.tar.gz文件
+gzip usr.tar
+# file1.txt压缩为file1.txt.gz文件
+gzip file1.txt
+# 将压缩文件usr.tar解压,并列出详细的信息
+gzip –dv usr.tar.gz
+```
+
+### `unzip`命令:压缩和解压缩文件(zip拓展)
+
+>基本语法:*unzip [选项] 文件名.zip*
+>>选项说明:
+>>
+>>`-x`文件列表 解压缩文件,但不包括指定的file文件。
+>>
+>>`-v`查看压缩文件目录,但不解压。
+>>
+>>`-t`测试文件有无损坏,但不解压。
+>>
+>>`-d`目录 把压缩文件解到指定目录下。
+>>
+>>`-z`只显示压缩文件的注解。
+>>
+>>`-n`不覆盖已经存在的文件。
+>>
+>>`-o`覆盖已存在的文件且不要求用户确认。
+>>
+>>`-j`不重建文档的目录结构,把所有文件解压到同一目录下
+
+```shell
+# 将压缩文件text.zip在当前目录下解压缩
+uzip text.zip
+```
+
+## 编辑命令vi
+
+### vi编辑器介绍
+
+vi 编辑器是 Linux 系统下的标准编辑器,vi 可以分为三种状态,分别是命令行模式、插入模式和底行模式,各模式的功能区分如下:
+
+* 命令行模式:控制屏幕光标的移动,字符、字或行的删除,移动复制某区段及进入插入模式下,或者到底行模式
+* 插入模式:只有在插入模式下,才可以做文字输入,按 ESC 键可回到命令行模式
+* 底行模式:将文件保存或退出 vi ,也可以设置编辑环境,如寻找字符串、列出行号等
+
+在使用时通常把 vi 简化成两个模式,将底行模式也算入命令行模式
+
+### 命令模式(Command mode)
+
+启动 vi ,在系统提示符号输入 vi 及文件名称后,就进入 vi 全屏幕编辑画面,处于命令行模式,可移动光标、删除、移动、复制
+
+>`i`当前光标前插入
+>
+>`a`当前光标后插入
+>
+>`o`当前光标所在行下插入空行
+>
+>`I`当前光标所在行上插入空行
+>
+>`A`插于行首
+>
+>`O`插于行尾
+>
+>`x`删除一个字符
+>
+>`dd`删除光标所在的行
+
+### 插入模式(Insert mode)
+
+切换到插入模式才能够输入文字,在命令行模式下按下字母 i 进入插入模式,进行字符的输入和文件的编辑
+
+>按`ESC`返回命令模式
+>
+>按`ESC`后输入“:”,进入底行模式
+
+### 底行模式(Lastline mode)
+
+在命令行模式下,按一下冒号 :键进入底行模式
+
+>`: w 文件名` 将文件以指定文件名保存
+>
+>`: wq` 输入wq,存盘并退出vi
+>
+>`: q!` 输入q!,不存盘强制退出vi

+ 369 - 0
docs/Lab/Lab2.md

@@ -0,0 +1,369 @@
+---
+sidebar: auto
+---
+
+# 进程创建与进程间通信
+
+## 本章导读
+
+本章意在介绍进程创建和进程间通信相关知识,
+
+## 进程创建
+
+### 什么是进程?
+
+通过操作系统这门课我们知道,在多道程序环境下,允许多个程序并发执行,此时它们将失去封闭性,并具有间断性及不可再现性的特征。为此引入了进程的概念,以便更好地描述和控制程序的并发执行,实现操作系统的并发性和共享性(最基本的两个特性)。
+
+**进程**表示程序的一次执行过程,它是应用程序的运行实例,是一个动态的过程。或者可以更简单地描述为:进程是操作系统当前运行的程序。当一个进程开始运行时,就是启动了这个过程。进程包括动态执行的程序和数据两部分。
+
+为了对系统中的所有进程实施有效的管理,引入了**进程控制**的概念,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。
+
+### 创建进程
+
+在Linux系统中,除了系统启动之后的第一个进程由系统来创建,其余的进程都必须由已存在的进程来创建,新创建的进程叫做**子进程**,而创建子进程的进程叫做**父进程**。那个在系统启动及完成初始化之后,Linux自动创建的进程叫做**根进程**。**根进程**是Linux中所有进程的祖宗,其余进程都是根进程的子孙。另外,具有同一个父进程的进程叫做**兄弟进程**。
+
+进程创建的过程示意图如下所示:
+
+![图片1](../.vuepress/public/process.png '进程的创建')
+
+### 系统调用fork()
+
+在Linux中,父进程以分裂的方式来创建子进程,为了在一个进程中分裂出子进程,Linux提供了一个系统调用`fork()`。这里所说的分裂,实际上是一种复制。因为在系统中表示一个进程的实体是**进程控制块(PCB)**,创建新进程的主要工作就是要创建一个新控制块,而创建一个新控制块最简单的方法就是复制。
+
+当然,这里的复制并不是完全复制,因为父进程控制块中某些项的内容必须按照子进程的特性来修改,例如进程的标识、状态等。另外,子进程控制块还必须要有表示自己父进程的域和私有空间,例如数据空间、用户堆栈等。
+
+进程调用`fork()`,当控制转移到内核中的fork代码后,内核会做:
+
+* 分配新的内存块和内核数据结构给子进程。
+* 将父进程部分数据结构内容拷贝至子进程。
+* 添加子进程到系统进程列表当中。
+* fork返回,开始调度器调度。
+
+在父进程中调用`fork()`之后会产生两种结果:一种为分裂子进程失败,另一种就是分裂子进程成功。`fork()`调用的一个奇妙之处在于它仅仅被调用一次,却能够返回两次,可能有三种不同的返回值:
+
+1. 在父进程中,返回新创建子进程的进程ID;
+2. 在子进程中,返回0;
+3. 如果出现错误,返回一个负值。
+
+在`fork()`执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。我们可以通过`fork()`返回的值来判断当前进程是子进程还是父进程。
+
+>为什么子进程返回0,父进程返回子进程的PID?
+>>我们可以这样理解,进程形成了链表,`fork()`返回的是进程的fpid,父进程的fpid指向子进程的进程id, 因为子进程没有子进程,所以其fpid为 0。
+
+>为什么`fork()`会返回两次?
+>>在fork函数内部执行return语句之前,子进程就已经创建完毕了,那么之后的return语句不仅父进程需要执行,子进程也同样需要执行,这就是fork函数有两个返回值的原因。
+
+**fork常规用法**
+
+* 一个进程希望复制自己,使子进程同时执行不同的代码段。例如父进程等待客户端请求,生成子进程来处理请求。
+* 一个进程要执行一个不同的程序。例如子进程从fork返回后,调用exec函数。
+
+**fork调用失败的原因**
+
+fork函数创建子进程也可能会失败,有以下两种情况:
+
+1. 系统中有太多的进程,内存空间不足,子进程创建失败。
+2. 实际用户的进程数超过了限制,子进程创建失败。
+
+## 与进程相关的系统调用
+
+### execv系统调用
+
+为了在程序运行中能够加载并运行一个可执行文件,Linux提供了系统调用 execv()
+
+将一个可执行的二进制文件覆盖在新进程的用户级上下文的存储空间上,以更改新进程的用户级上下文。调用进程被覆盖,从新程序的入口开始执行,这样就产生了一个新进程,进程标识符id不变。
+
+**函数原型**
+
+>参数 path 为可执行文件路径,argv[] 为命令行参数
+
+```c
+int execv(const char* path, char* const argv[]);
+```
+
+**返回值**
+
+如果应用程序正常执行完毕,那么 execv 是永远不会返回的;当 execv 在调用进程中返回时,那么这个应用程序应该出错了,此时它的返回值应该是 -1,失败原因存于 errno 中
+
+**范例**
+
+```c
+// 执行/bin/ls -al /etc/passwd 
+#include<unistd.h>
+main()
+{
+    char * argv[ ]={“ls”,”-al”,”/etc/passwd”,(char*)};
+    execv(“/bin/ls”,argv);
+}
+```
+
+>实际上存在一个 exec函数族,execv() 只是其中一个,他们的区别主要是
+>
+>1. 待执行的程序文件是由文件名(filename)还是由路径名(pathname)指定;
+>2. 新程序的参数是一一列出还是由一个指针数组来引用;
+>3. 把调用进程的环境传递给新程序还是给新程序指定新的环境
+>
+>其作用都是相同的
+
+### wait系统调用
+
+为使父进程在子进程结束之后释放子进程所占用的系统资源,父进程应该调用系统调用`wait()`。父进程与子进程同步,父进程调用后,进入睡眠状态,直到子进程结束或者父进程被其他进程终止。
+
+**系统调用格式:**
+
+```c
+void exit(int *status)
+```
+
+内核对wait( )作以下处理:
+
+1. 首先查找调用进程是否有子进程,若无,则返回出错码;
+2. 若找到僵死进程,则将子进程的执行时间加到父进程的执行时间上,并释放子进程的进程表项;
+3. 若未找到僵死进程,则调用进程便在可被中断的优先级上睡眠,等待其子进程发来软中断信号时被唤醒。
+
+>僵死进程:一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中,也就是进程为中止状态。
+
+### exit系统调用
+
+如果一个进程调用exit(),系统会立即停止所以操作,清除进程相关的各种数据结构,包括进程PCB,并且终止当前进程的运行。
+
+**系统调用格式:**
+
+```c
+void exit(int status)
+```
+
+其中,status 是返回给父进程的一个整数,0 表示正常退出,其他表示非正常退出,一般使用 -1 或者 1。
+
+**进程终止的特殊情况**
+
+1. 子进程终止时,父进程并没有在执行 wait() 调用。
+
+这时进程处于上文所提到僵死状态,处于这种状态的进程不使用任何内核资源,但是要占用内核中的进程处理表那的一项。当其父进程执行 wait() 等待子进程时,它会进入睡眠状态,然后把这种处于过渡状态的进程从系统内删除,父进程仍将能得到该子进程的结束状态。
+
+2. 当子进程尚未终止时,父进程却终止了。
+
+对于⽗进程已经终⽌的所有子进程,他们的⽗进程都改变为 init 进程。我们称这些子进程由 init 领养。⼀个init的⼦进程(包括领养进程)终⽌时,init会调⽤⼀个 wait() 函数取得其终⽌状态。
+
+### lockf系统调用
+
+lockf()函数对指定区域的资源进行加锁或解锁,以实现进程的同步或互斥。
+
+**系统调用格式:**
+
+```c
+#include <unistd.h>
+int lockf(int fd, int mod, int size)
+```
+
+>**fd** 是打开文件的文件描述符
+>
+>**mod** 是指定要采取的操作的控制值。1是进行锁定,0是解锁
+>
+>**size** 是要锁定或解锁的连续字节数
+
+两个常用命令:
+
+1. 当 size = 0 时是个特殊情况,它代表锁定区域从该函数到程序结尾。lockf(1,1,0)意思是该进程的编号为1,并对进程的资源进行锁定,锁定区域从该函数到程序结尾。
+2. lockf(1,0,0)是对编号为 1 的进程进行解锁,释放资源。
+
+## 进程间通信
+
+### 进程间通信的概念
+
+进程用户空间是相互独立的,一般是不能相互访问的。但很多情况下进程之间需要互相通信,来完成系统的某项功能。进程通过与内核及其它进程之间的互相通信来协调它们的行为。
+
+Linux环境下的进程间通信(Inter-Process Communication,简称IPC)有多种工具可以使用,如:无名管道pipe、命名管道FIFO、消息队列、共享内存、信号量、信号、文件锁、socket等。这些IPC工具以系统调用或库函数API的形式提供给用户使用,用户使用这些API可以在不同的进程之间传输数据、同步进程、或者发送信号。
+
+每一种IPC通信工具,都有自己的优缺点、使用场合和局限,我们只有全面了解和掌握各个IPC工具的使用,知晓其优缺点,才能根据需要,选择合适的通信机制。
+
+### 无名管道(pipe)
+
+无名管道又称匿名管道,是一种半双工的通信方式,数据只能单向流动,而且只能在具有亲缘关系的进程间使用,进程的亲缘关系一般指的是父子关系。无名管道一般用于两个不同进程之间的通信。当一个进程创建了一个管道,并调用fork创建自己的一个子进程后,父进程关闭读管道端,子进程关闭写管道端,这样提供了两个进程之间数据流动的一种方式。
+
+这是一种最基本的IPC机制,由**pipe函数**创建:
+
+```c
+#include <unistd.h>
+int pipe(int fd[2]);
+```
+
+pipe 函数的参数是一个包含两个 int 类型整数的数组指针。该函数成功时返回 0,并将一对打开的文件描述符值填入其参数指向的数组。如果失败,则返回 -1 并设置 errno。
+
+通过pipe函数创建的这两个文件描述符fd[0]和fd[1]分别构成管道的两端,往fd[1]写入的数据可以从fd[0]读出,并且fd[1]一端只能进行写操作,fd[0]一端只能进行读操作,不能反过来使用。要实现双向数据传输,可以使用两个管道。
+
+### 命名管道(FIFO)
+
+命名管道也是一种半双工的通信方式,但不用同于无名管道之处在于它提供一个路径名与之关联,以命名管道的文件形式存储文件系统中。命名管道是一个设备文件,因此即使进程与创建命名管道的进程不存在亲缘关系,只要可以访问该路径,就能够通过命名管道相互通信。
+
+Linux中通过系统调用`mknod()`或`mkfifo()`来创建一个命名管道。最简单的方式是通过直接使用shell:
+
+```shell
+# 在当前目录下创建了一个名为myfifo的命名管道
+# 两者等价
+mkfifo myfifo
+mknod myfifo p
+```
+
+返回值:均是成功返回0,失败返回-1。
+
+### 用于管道通信的函数
+
+#### `read()`
+
+从指定文件中读数据,并将它们送至所指示的缓冲区中。
+
+**系统调用格式:**
+
+```c
+#include <unistd.h>    
+ssize_t read(int fd, void *buf, size_t count); 
+```
+
+>**fd** 是打开文件的文件描述符
+>
+>**buf** 是指定缓冲区的指针
+>
+>**count** 是要读取的字节数
+
+返回值:成功则返回读取的字节数,出错则返回 -1 并设置 errno,如果在调 read 之前已到达文件末尾,则这次read返回 0。
+
+#### `write()`
+
+从指定文件中读数据,并将它们送至所指示的缓冲区中。
+
+**系统调用格式:**
+
+```c
+#include <unistd.h>    
+ssize_t write(int fd, const void *buf, size_t count); 
+```
+
+>**fd** 是打开文件的文件描述符
+>
+>**buf** 是指定缓冲区的指针
+>
+>**count** 是要写入的字节数
+
+返回值:成功返回写入的字节数,出错返回-1并设置errno写常规文件时,write的返回值通常等于请求写的字节数count。
+
+>管道作为临界资源,使用过程中父子进程之间除了需要读写同步以外,在对管道进行读写操作时还需要互斥进入,可以使用对文件上锁和开锁的系统调用lockf()。如果文件被加锁,将会等待,直到锁打开为止。
+
+### 信号
+
+信号是比较复杂的通信方式,类似于Windows下的消息,用于通知接受进程有某种事件发生。除了用于进程间通信外,进程还可以发送信号给进程本身。Linux除了支持Unix早期信号语义函数`signal`外,还支持语义符合Posix.1标准的信号函数`sigaction`。
+
+每个信号都对应一个正整数常量(signal number,即信号编号),代表同一用户的诸进程之间传送事先约定的信息的类型,用于通知某进程发生了某异常事件。每个进程在运行时,都要通过信号机制来检查是否有信号到达。若有,便中断正在执行的程序,转向与该信号相对应的处理程序,以完成对该事件的处理;处理结束后再返回到原来的断点继续执行。实质上,信号机制是对中断机制的一种模拟,故在早期的UNIX版本中又把它称为软中断。
+
+信号的处理方式有3种:
+
+1. 忽略(放置不理)
+2. 默认处理方式(会终止一个进程)
+3. 响应信号处理(信号发生时执行预先编写的函数)
+
+#### 信号相关函数
+
+`signal`函数:信号处理
+
+```c
+void(*signal(int sig,void (*func)(int)(int)))
+```
+
+>**sig** 信号值
+>
+>**func** 信号处理的函数指针,参数为信号值
+
+`sigaction`函数
+
+```c
+int sigaction(int sig,const struct sigaction *act,struct sigaction *oact)
+```
+
+>**sig** 信号值
+>
+>**act** 指定信号的动作,相当于func
+>
+>**oact** 保存原信号的动作
+
+`kill`函数
+
+把信号sig发送给pid进程,成功时返回0;当给定的信号无效、发送权限不够或目标进程不存在,则失败
+
+```c
+int kill(pid_t pid,int sig)
+```
+
+>**pid** 进程id
+>
+>**sig** 信号值
+
+`alarm`函数
+
+提供一个闹钟的功能,进程可以调用alarm函数在经过预定时间时发送一个SIGALRM信号(定时信号)
+
+```c
+unsigned int alarm(unsigned int seconds)
+```
+
+>**seconds** 时间
+
+### 信号量
+
+为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问代码的临界区域。我们可以使用信号量。
+
+信号量本身只是一种外部资源的标识,不具有数据交换功能,而是通过控制其他的通信资源实现进程间通信。可以用来控制多个线程对共享资源的访问,亦或作为一种锁机制,防止某进程在访问资源时其它进程也访问该资源。因此,信号量主要责数据操作过程中的互斥,同步等功能。
+
+可以这样理解,信号量是一个计数器,当有进程对它所管理的资源进行请求时,进程先要读取信号量的值:若大于0,资源可以请求;若等于0,资源不可以用,这时进程会进入睡眠状态直至资源可用。当一个进程不再使用资源时,信号量+1(V操作),反之当有进程使用资源时,信号量-1(P操作)。对信号量的值操作均为原子操作。
+
+Linux提供了一组精心设计的信号量接口来对信号进行操作,不只是针对二进制信号量,另外,这些函数都是用来对成组的信号量值进行操作的。它们声明在头文件sys/sem.h中。
+
+```c
+#include <sys/sem.h>
+// 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
+int semget(key_t key, int num_sems, int sem_flags);
+// 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
+int semop(int semid, struct sembuf semoparray[], size_t numops);  
+// 控制信号量的相关信息
+int semctl(int semid, int sem_num, int cmd, ...);
+```
+
+### 消息队列
+
+消息队列亦称报文队列,也叫做信箱。这种通信机制传递的数据具有某种结构,而不是简单的字节流。本质其实是一个内核提供的链表,内核基于这个链表,实现了一个数据结构,向消息队列中写数据,实际上是向这个数据结构中插入一个新结点;从消息队列汇总读数据,实际上是从这个数据结构中删除一个结点。
+
+消息队列克服了信号传递信息少,管道只能承载无格式字节流以及缓冲区大小受限等特点。对消息队列具有操作权限的进程可以使用函数完成对消息队列的操作控制。通过使用消息类型,进程可以按任何顺序读信息,或为消息安排优先级顺序。
+
+#### 消息队列相关函数
+
+```c
+#include <sys/msg.h>
+// 创建消息队列: 成功将返回该消息队列的标识码;失败则返回 -1
+int msgget(key_t key, int msgflg);
+// 添加信息到消息队列: 成功返回0,失败返回-1
+int msgsnd(int msgid, const void *msg_ptr, size_t msg_sz, int msgflg); 
+// 从消息队列中读取消息: 成功返回实际放到接收缓冲区里去的字符个数失败,则返回 -1
+int msgrcv(int msgid, void *msg_ptr, size_t msgsz,long int msgtype, int msgflg);
+// 消息队列的控制函数: 成功返回0,失败返回-1
+int msgctl(int msqid, int command, strcut msqid_ds *buf);
+```
+
+### 共享内存
+
+共享内存就是映射一段能被其他进程所访问的内存,这段共享内存由一个进程创建,但多个进程都可以访问,一个进程写入共享内存的信息,可以被其他使用这个共享内存的进程,通过一个简单的内存读取错做读出,从而实现了进程间的通信。往往与其他通信机制,如信号量,配合使用。
+
+采用共享内存进行通信的一个主要好处是效率高,因为进程可以直接读写内存,而不需要任何数据的拷贝,对于像管道和消息队里等通信方式,则需要再内核和用户空间进行四次的数据拷贝,而共享内存则只拷贝两次:一次从输入文件到共享内存区,另一次从共享内存到输出文件。
+
+一般而言,进程之间在共享内存时,并不总是读写少量数据后就解除映射,而是保持共享区域,直到通信完毕为止。这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存中的内容往往是在解除映射时才写回文件。
+
+### 套接字
+
+前面说到的进程间的通信,所通信的进程都是在同一台计算机上的,而使用socket进行通信的进程可以是同一台计算机的进程,也可以是通过网络连接起来的不同计算机上的进程。通常我们使用socket进行网络编程。
+
+socket,即套接字,是一种通信机制,凭借这种机制,客户/服务器系统的开发工作既可以在本地单机上进行,也可以跨网络进行。也就是说它可以让不在同一台计算机但通过网络连接计算机上的进程进行通信。也因为这样,套接字明确地将客户端和服务器区分开来。
+
+套接字的特性由3个属性确定:
+
+1. **域**:指定套接字通信中使用的网络介质,最常见的套接字域是AF_INET,它指的是Internet网络。
+2. **类型**:因特网提供了两种通信机制:流(stream)和数据报(datagram),因而套接字的类型也就分为流套接字和数据报套接字。
+3. **协议**:只要底层的传输机制允许不止一个协议来提供要求的套接字类型,我们就可以为套接字选择一个特定的协议。通常只需要使用默认值。
+