冯诺依曼体系结构
计算机都是由一个个硬件组件组成:
- 输入设备:键盘、鼠标等
- 输出设备:显示器、打印机
- 存储器:内存
- 中央处理器(CPU):运算器、控制器组成
ps:不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备) ;外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取;所有设备都只能直接和内存打交道。硬件结构决定软件行为,所有设备都是围绕存储器工作的。
操作系统
概念:
操作系统是管理计算机硬件与软件资源的计算机程序,同时也是计算机系统的内核与基石。笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等)
目的:
- 与硬件交互,管理所有的软硬件资源
- 为用户程序(应用程序)提供一个良好的执行环境
定位:
- 搞管理的软件
管理方法:
- 先描述起来:用 struct 结构体
- 在组织起来:用链表或者其他高效的数据结构
系统调用和库函数:
- 操作系统对外会表现为一个整体,但是会暴露自己的部分接口供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,库函数封装了系统调用接口,从而形成库,有了库就很有利于更上层用户或者开发者进行二次开发。
进程介绍
进程概念:
进程就是一个运行中的程序,对于操作系统来说进程就是一个PCB,这个PCB是一个进程控制块,它是一个运行中程序的描述,操作系统通过这个PCB的描述来控制程序的运行。在Linux下这个PCB实际上是一个结构体 task_struct,如何查看这个结构体?
大概在文件 sched.h 中 1342 行附近。
进程如何描述一个运行中的程序?
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针 。
- 上下文数据: 进程执行时处理器的寄存器中的数据
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
查看进程
- 进程的信息可以通过 /proc 系统文件夹查看。举例:如果要获取PID为1的进程信息,你需要查看 /proc/1 这个文件夹。
- 通过 ps 指令来查看进程,ps命令用于报告当前系统的进程状态。可以搭配kill指令随时中断、删除不必要的程序。ps命令是最基本同时也是非常强大的进程查看命令,使用该命令可以确定有哪些进程正在运行和运行的状态、进程是否结束、进程有没有僵死、哪些进程占用了过多的资源等等,总之大部分信息都是可以通过执行该命令得到的。
ps -aux:
ps -ef:
通过系统调用创建进程
-
pid_t fork(void);
父子进程代码共享,数据各自开辟空间是独有的。(采用写时拷贝技术) -
代码举例:
#include <stdio.h>
#include <unistd.h>
int main()
{
int ret = fork();
if(ret < 0)
{
perror("fork");
return 1;
}
else if(ret == 0)
{ //child
printf("I am child : %d, ret: %d\n", getpid(), ret);
}
else
{ //father
printf("I am father : %d, ret: %d\n", getpid(), ret);
}
sleep(1);
return 0;
}
进程状态
-
R: 运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
-
S:睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptiblesleep)。
-
D :磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
-
T:停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可 以通过发送 SIGCONT信号让进程继续运行。PS:在某一程序运行时,输入 CTRL+Z(让进程停止,并不是让进程退出) 可以使该进程变为 T 状态的进程。
-
X:死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
-
Z:僵死状态(zombie):进程已经退出,但是资源没有完全释放。
僵尸进程
- 产生原因:子进程先于父进程退出,为了保存退出原因,因此资源并没有完全释放。因此在子进程退出时,操作系统会通知父进程,让父进程获取子进程的退出原因,然后释放子进程的所有资源。如果父进程当前并没有关注子进程的状态,则子进程将会成为僵尸进程
- 僵尸进程的危害:进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程)可父进程如果一直不读取,那子进程就一直处于Z状态,维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,也就是说,Z状态一直不退出,PCB一直都要维护,所以才会造成内存资源的泄漏。
- 僵尸进程的避免:进程等待
- 僵尸进程的处理:退出父进程
孤儿进程
- 产生原因:父进程先于子进程退出,子进程成为孤儿进程,运行在后台。此时,孤儿进程被1号 init 进程领养,他的父进程成为1号进程(init进程)。PS:此时孤儿进程退出不会成为僵尸进程
守护进程/精灵进程
- 它是一个特殊的孤儿进程,在孤儿进程的基础上,脱离终端、脱离登录会话,通常运行在后台默默地工作,不希望受到终端会话的影响。
进程优先级
-
在Linux下,用 ps –fl 命令查看进程会出现以下:
PR I就是进程的优先级,此值越小,进程的优先级别越高 、此值越大,进程的优先级别越低。NI 就是 nice 值,其表示进程可被执行的优先级的修正数。PRI 值越小越快被执行,那么加入 nice 值后,将会使得PRI变为:PRI(new)=PRI(old)+nice 。在 Linux 下,调整进程优先级就是调整 nice。nice其取值范围是-20至19,一共40个级别。PS:进程的 nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进 程的优先级变化 。 -
指令设置进程优先级
原来 优先级:
指令:
①:renice -n 10 -p 3169 或者 nice -n 10 ./test(test 为可执行文件)
②:输入top指令–>进入top后按“r”–>输入进程PID–>输入nice
PS:将优先级升高(即将nice值减小时),需要 root 权限。
环境变量
概念:
- 存放系统运行环境参数的变量
相关指令:
- env:显示所有环境变量
- echo:显示某个环境变量值(使用时需要加上$符号)
其中在 /usr/bin 目录下存放的是指令:比如 ls 、pwd 、cp、mv 等等 - set:显示本地定义的shell变量和环境变量
- export: 设置一个新的环境变量
- unset:清除环境变量
常见环境变量:
-
PATH : 指定命令的搜索路径
为什么有些指令可以直接执行,不需要带路径,而我们的二进制程序需要带路径才能执行? 可以将二进制程序放到环境变量PATH当中的路径中,我这样子做就可以不用带路径执行程序:
也可以将我们的程序所在路径加入环境变量PATH当中:
-
HOME : 指定用户的主工作目录(就是用户登陆到Linux系统中时默认的目录)
-
SHELL : 当前Shell,它的值通常是 /bin/bash
通过代码获取环境变量:
- 命令行第三个参数获取
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
int i = 0;
for(i; env[i]; i++)
{
printf("env[%d] = %s\n",i,env[i]);
}
return 0;
}
- 通过第三方变量environ获取
#include <stdio.h>
int main(int argc, char *argv[], char *env[])
{
//libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明
extert char** environ;
int i = 0;
for(i; environ[i] != NULL; i++)
{
printf("environ[%d] = %s\n",i,environ[i]);
}
return 0;
}
通过系统调用获取( getenv)或 设置( putenv )环境变量的内容 :
- getenv:通过环境变量名称获取内容,用 getenv 函数可以通过给出 name 来获得 value 的值。
26 //char* getenv(const char* name); name:想要获取的环境变量名
27 //通过环境变量名称获取内容
28 char* ptr = getenv("PATH");
29 if(ptr == NULL)
30 {
31 printf("have no PATH\n");
32 }
33 else
34 {
35 printf("PATH=%s\n",ptr);
36 }
37 return 0;
38 }
- putenv:用来改变或增加环境变量的内容,如果环境表中没有 name 这个环境变量,则添加该环境变量;如果环境表中已经有了name这个环境变量,则先删除之前的 value,再修改为新的 value。
#include<stdio.h>
#include<stdlib.h>
int main()
{
int ret = putenv("MYTEST=123");
if(ret != 0)
{
printf("putenv error!\n");
}
else
{
printf("putenv complete!\n");
}
return 0;
}
环境变量的特性与作用
- 环境变量通常具有全局属性,可以被子进程继承下去。
#include <stdio.h>
#include <stdlib.h>
int main()
{
char* env = getenv("MYENV");
if(env)
{
printf("MYENV=%s\n", env);
}
return 0;
}
直接查看,发现没有结果,说明该环境变量根本不存在,导出环境变量 export MYENV="hello world"再次运行程序,输出 MYENV=hello world。
- 环境变量可以让系统运行环境参数配置起来更加灵活。