2017-2018-1 20155223 《信息安全系统设计基础》第14周学习总结
教材内容学习总结
进程控制
获取进程
每个进程都有唯一一个正数进程ID。函数getpid返回目标进程的ID,函数getppid返回目标进程的父进程ID。
创建进程和终止进程
从程序员角度,进程被认为总是处在以下三种状态之一:
- 运行 进程要么正在CPU上执行,要么是在等待被执行借最终会被内核调度。
- 停止 进程的执行被挂起,且不会被调度。当进程收到SIGSTOP、SIGTSTP、SIGTTIN或SIGTTOU信号时,进程就停止,并保持停止直到收到SIGCONT信号,在这个时刻,进程再次开始运行。
- 终止 进程永远地停止了。进程因为三种原因终止:收到一个信号,该信号的默认行为是永远终止进程;从主程序返回;调用exit函数。
父进程通过调用fork函数来创建子进程。
子进程几乎但不完全和父进程相同。新诞生的子进程享有父进程用户级的虚拟地址空间相同的一份副本,包括代码和数据段、对、共享库以及用户栈。子进程还获得与父进程任何打开文件描述符相同的副本,即子进程可以读写父进程中打开的任意文件。子进程与父进程之间最大的区别是它们的ID。
fork函数只被调用一次,却会返回两次:一次是在父进程中,另一次是在子进程中。在父进程中,fork返回诞生的子进程的PID;在子进程中,fork返回0。因为子进程的PID不为0,所以可以通过返回值来分辨程序是在子进程还是在父进程中运行了。
一个嵌套fork函数的程序,fork的返回次数为2的被嵌套次数次方个。
回收进程
当一个进程由于某种原因终止是,内核并不是立即把它从系统中清除。相反,进程被保持在一种已终止的状态中,直到它被父进程回收。
如果一个父进程终止了,内核会安排init进程成为它的孤儿进程的养父。init进程的PID为1,是在系统启动时由内核创建的,它不会终止,是所有进程的祖先。如果父进程没有回收它的僵死子进程就终止了,那么内核会安排init进程来回收。
一个进程可以通过函数waitpid来等待其子进程终止或停止。
#include <sys/types.h>
#include <sys/wait.h>
pid_t waitpid(pid_t pid, int *statusp, int options);
wait函数是waitpid函数的简单版本:
#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *statusp);
调用wait(&status)等价于调用waitpid(-1,&status,0)。
让进程休眠
sleep函数将一个进程挂起一段指定的时间。
#include <unistd.h>
unsigned int sleep(unsigned int secs);
如果请求时间到了,sleep函数返回0,否则就是返回剩余休眠秒数。
信号
系统信号列表:
用kill函数发送信号
进程通过调用kill函数发送信号给其他进程(包括它们自己)。
#include <sys/types.h>
#include <signal.h>
int kill(pid_t pid, int sig);
如果pid大于0,那么kill函数发送信号号码sig给进程pid。如果pid等于0,那么kill发送信号sig给调用进程所在进程组的每个进程,包括调用进程自己。如果pid小于0,kill发送信号sig给进程组|pid|中的每一个进程。
所以函数kill并不能够杀死任意进程,而是只能发送信号。
课后习题
8.25
编写fegts函数的一个版本,叫做tfgets,它5秒钟后会超时。tfgets函数接收和fgets相同的输入。如果用户在5秒内不键入一个输入行,tfgets返回NULL。否则,它返回一个只想输入行的指针。
分析
fgets的定义如下:
char fgets(char buf, int bufsize, FILE stream);
参数:
buf: 字符型指针,指向用来存储所得数据的地址。
bufsize: 整型数据,指明buf指向的字符数组的大小。
*stream: 文件结构体指针,将要读取的文件流。
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <signal.h>
#include <setjmp.h>
sigjmp_buf env;
void tfgets_handler(int sig)
{
signal(SIGALRM, SIG_DFL);
siglongjmp(env, 1);
}
char *tfgets(char *buf, int bufsize, FILE *stream)
{
static const int TimeLimitSecs = 5;
signal(SIGALRM, tfgets_handler)
alarm(TimeLimitSecs);
int rc = sigsetjmp(env, 1);
if(rc == 0) return fgets(buf, bufsize, stream);
else return NULL; //alarm,time out
}
显然,在tfgets里一开始需要调用fgets。然而,因为五秒时间到了,fgets还没有返回,所以我们必须在处理程序里直接跳转到某个地方进行tfgets的NULL返回。这就需要用到非本地跳转。
代码托管
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 31/31 | 1/1 | 20/20 | |
第三周 | 24/55 | 2/3 | 24/44 | 知道浮点数怎么储存的 |
第四周 | 177/328 | 2/5 | 17/61 | 现在我的C语言程序也会在Linux命令行下使用了:*) |
第五周 | 54/382 | 2/7 | 18/79 | 复习一遍汇编语言 |
第七周 | 2360/2722 | 1/8 | 12/91 | |
第八周 | 624/3344 | 2/10 | 19/110 | 了解多线程和多进程 |
第九周 | 1112/4456 | 3/13 | 15/125 | 学习怎么实现pwd命令 |
第十一周 | 157/4613 | 2/15 | 10/135 | 在紧急情况下恢复不可使用的虚拟机 |
第十三周 | 999/5471 | 2/17 | 17/152 | 回顾了线程部分的内容 |
第十四周 | 181/5652 | 1/18 | 10/162 |