linux系统的目录是一个倒状树
顶层 根目录 /
bin 命令
boot 系统内核以及系统启动的文件
dev 系统硬件设备
etc 系统配置文件
lib 系统库
proc 系统内存的信息 (虚拟 内存在磁盘上的映射)
usr 不常改变的程序
var 经常改变的(日志/邮件...)
基本操作
cd + 位置 可以跳转
cd .. 退到上一层
ctrl+l 或者 clear 清屏
ls -l 看文件类型
普通文件 -
管道文件 p
命令:
文件: mv 移动 cp 拷贝 rm删除 touch 创建普通文件 mkdir 创建文件夹 cat查看文件 more less head tail vi/vim find 查找文件 grep 过滤
进程: ps 查看进程 kill 结束进程 & 将进程放入后台执行
gcc gdb 静态库 共享库
两个库在使用上的区别: 静态库 每一个用户在使用是都需要加载进自己的程序 共享库则直接调用即可
printf 缓冲区内容被输出到屏幕三种方法:1 缓冲区放满 2 缓冲区未满 强制刷新 3 程序结束
程序执行结果会存放在缓冲区 当进程结束后 缓冲区数据展现出来,\n会强制刷新缓冲区
exit(0) 1. 刷新缓冲区2. 退出进程 调用_exit()
刷新缓冲区另一种方法 fflush(stdout) // stdin/stdout 屏幕标准输入/输出 stderr 标准错误输出 (类型FIFE*)
main 参数
fork 复制进程
linux vim中结束语句一般是exit(0); (头文件#include<stdlib.h>)
0代表成功 1代表失败
gcc -o 生成文件名 运行文件名
./生成文件名
echo 打印
pwd 显示工作路径
main函数参数有三(int参数个数argc; char*参数内容argv[]; char*环境变量envp[])
可以从主函数 拿到用户传入的参数
echo $PATH // $ 打印PATH的值
echo PATH // 不加$打印PATH
int main(int argc, char* argv[], char* envp[])
{
printf("argc=%d\n",argc);
int i = 0;
for(; i < argc; i++)
{
printf("argv[%d] = %s\n", i, argc[i]);
}
for(i = 0; envp[i] != NULL; i++)
{
printf("envp[%d] = %s\n", i, envp[i]);
}
exit(0);
}
![](https://i-blog.csdnimg.cn/blog_migrate/552ee6ae20a210a25067b1b423651f40.png)
计算机抽象图
手机存储6 + 128 (6 内存大小 128 硬盘大小)
main.c and main程序都存放在硬盘中,执行./main时通过I/O设备传入内存
内存重点数据在断电后就没有了
程序: 由一条条指令组成 (菜谱)
程序运行时产生进程 (厨房)
进程执行一条条指令
操作系统:管理计算机上软硬件资源 (管理内存 进程 文件)
为什么main.c程序需要编译成main.exe/main可执行文件 才可以执行呢?
计算机只可以执行二进制的指令(0101) 这样的指令集合称之为指令系统
linux上可执行文件格式 | ELE |
windows上可执行文件格式 | PE |
进程
进程控制块PCB 用结构体实现的 链表 每个链表节点中存放进程信息
操作系统中 进程控制块是进程存在的唯一信息
struct task_struct;
{
int pid; // 进程id
int status; //进程状态
...
}
![](https://i-blog.csdnimg.cn/blog_migrate/92160e8dff145ceaa4e64130f527f5ce.png)
linux的内核-C语言 1991 芬兰学生第一个版本
进程基础三状态 : 就绪 运行 阻塞
就绪 | 其他信息都准备好了,等待处理器调动 |
运行 | CPU处理器开始执行 |
阻塞 | 某个信息没有准备好,不能执行 |
![](https://i-blog.csdnimg.cn/blog_migrate/e433015e0223b12ffec37dbba0a348b1.png)
进程三状态
并发&并行
单位时间内交替执行 并发
两个处理器同时运行 并行
![](https://i-blog.csdnimg.cn/blog_migrate/8d521be55d035577a27b4e55a8470430.png)
并行 并发
内存管理
页表记录 逻辑页(程序)与物理页(内存)的关系 操作系统管理空闲的物理页,将逻辑页分配过去
![](https://i-blog.csdnimg.cn/blog_migrate/b60e9a283c5a890be74b9c495b814668.png)
32位 全零到全一 4G
进程地址空间
fork() 复制一个进程 父进程的fork返回值是子进程的id号 子进程中fork返回值是0
父进程的内存 -> 复制给子进程 (写时拷贝) , 父进程中fork后 子进程会从该fork后开始执行,fork前会复制过来
复制出来的子进程从pid_t pid = fork() 开始执行(将前面的运行结果对其也有影响) eg. 父进程开始n=0 那么子进程中的n也为0
父进程的父进程是bash,在终端中执行的命令时会先把bash复制一份
写时拷贝 : 为了提高fork效率,父子进程的内存页面改了就复制,没改就共享
父子进程 物理内存上n是否是同一个空间?? 不在
原因1 &n打印的是逻辑地址(偏移量) 不是真实的地址
原因2 fork后会复制父进程同样大小的空间给子进程
[有了逻辑地址和页表(在proc中存着)就可以计算出物理地址]
![](https://i-blog.csdnimg.cn/blog_migrate/ace6c175ed4c3f6229ab3d1331a8676e.png)
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/types.h>
int main(int argc, char* argv[], char*envp[])
{
int n = 0; // 定义一会要打印数据的个数
char * s = NULL; // 记录父子进程要打印的内容
pid_t pid = fork(); // err -1 运行到此 会复制出一个子进程 子进程会从此继续执行 父进程pid为子进程的进程号 子进程的pid为0
if(pid == -1)
{
exit(1);
}
if(pid == 0)
{
n = 3;
s = "child";
}
else
{
n = 7;
s = "parent";
}
for(int i = 0; i < n; i++)
{
printf("s = %s, curr_pid = %d, curr_ppid = %d, &n = %p, n = %d \n", s, getpid(), getppid(), &n, n); // pid 当前进程的id号 ppid是当前进程的父id号
sleep(1);
}
exit(0);
}
![](https://i-blog.csdnimg.cn/blog_migrate/5799c24d26d78142345e9354259fdc31.png)
僵死进程:子进程先结束,父进程没有wait获取子进程的退出码
解决办法: 1.父进程wait, wait可以使子进程不成为僵死进程
2. 父进程先结束,直接退出,子进程变成孤儿进程,孤儿进程由init进程(或其他进程)接管,由init进程执行wait
进程控制(wait 和 waitpid)的理解和使用https://blog.csdn.net/m0_46606290/article/details/123609793
./fork & (后台执行)
面试题
![](https://i-blog.csdnimg.cn/blog_migrate/cfd617e52039ec6dd05b95fcbd4179cc.png)
输出多少个A??? 三个
![](https://i-blog.csdnimg.cn/blog_migrate/7aaf5e7f6651caa84b25c259e9142f85.png)
逻辑或 A || B 三种可能
1 A为false(假),继续B判断,如果也为false(假),结果为false(假)
2 A为false(假),继续B判断,如果为true(真),结果为true(真)
3 A为true(真),则不再进行B判断,结果为true(真)
![](https://i-blog.csdnimg.cn/blog_migrate/1af66f78694b9d72fce2549854e3f5f0.png)
输出多少A??? 6个
![](https://i-blog.csdnimg.cn/blog_migrate/39164cebb15a435e231852596b0f3d51.png)
输出多少A??? 8个
![](https://i-blog.csdnimg.cn/blog_migrate/50eb1efdd62053524badbd03a5ec84c5.png)
输出两个A 原因:父进程的缓冲区有一个A,fork后 子进程将父进程的缓冲区也复制过来其中包含A,子进程结束后会将缓冲区内容输出 ,所以是两个A.