fork子进程,进程退出与等待
认识fork()头文件<unistd.h>提供的fork()函数用于从已有的原进程创建一个新的子进程,而原进程在关系式称为父进程
fork()的返回值12#include <unistd.h>pid_t id = fork();
父子进程中fork()函数的返回值(此处用变量id储存)是不同的:
父进程里id的值为子进程的PID,其值>0;子进程里id值固定为0
id > 0 父进程
id == 0 子进程
id < 0 fork()失败
分流https://picbed0521.oss-cn-shanghai.aliyuncs.com/blogpic/PixPin_2024-07-09_13-00-38.png
利用父子进程中fork()返回值的不同,可以用if...else...进行分流,让父子进程执行不同的代码
fork()的过程进程调用fork,当控制转移到内核中的fork代码后,内核做
分配新的内存块和内核数据结构给子进程
将父进程部分数据结构内容拷贝至子进程
添加子进程到系统进程列表当中
fork返回,开始调度器调度
ht ...
环境变量
基本概念
环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数
环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性
构成:环境变量是一系列字符串的统称,所以一个环境变量由变量名和值构成
这么说还是太抽象了,我们接下来会举几个具体样例,体会环境变量在获取系统全局的变量,系统指令路径等方面的作用
常见环境变量
变量名
功能
PATH
指定命令的搜索路径
HOME
指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
USER
当前用户名
SHELL
当前Shell,它的值通常是/bin/bash
PWD
当前工作目录
操作系统变量查看环境变量echo $NAME NAME为变量名
以PATH为例,查看PATH的值的指令为
1echo $PATH
https://picbed0521.oss-cn-shanghai.aliyuncs.com/blogpic/PixPin_2024-07-08_12-46-35.png
可以看到PATH的内容为多个文件路径,互相以:分隔
而若要查看 ...
初识进程
操作系统平台:Linux服务器系统: CentOS 7
概念抽象程序程序 = 代码 + 数据
程序是储存在硬盘上的可执行文件
进程将程序加载到内存后,就在内存中程序的就是进程。也就是说一个正在运行的程序就能叫做进程
结构关系如下
如图,操作系统为了管理内存中的进程,使用了PCB结构体来描述进程,通过管理PCB来管理进程,依然是先描述再组织
PCB:进程控制块的数据结构(process control block)
所以实际上:进程=PCB+代码和数据
对于代码和数据没什么好说的,接下来主要讨论PCB
task_structLinux平台下的PCB叫做task_struct
task_struct内容分类:
标示符: 描述本进程的唯一标示符,用来区别其他进程。
状态: 任务状态,退出代码,退出信号等。
优先级: 相对于其他进程的优先级。
程序计数器: 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据。
I/O状态信息: 包括显示的I/ ...
C/C++ static关键字的使用
因为static的用法又多又杂,值得单出一篇博客用以汇总
C/C++ 通用用法局部变量->全局属性当对原本声明在函数栈帧里的变量使用static修饰时,该变量的存储空间会改变到静态区,不会随着函数栈帧的销毁而销毁。
初始化:初次调用声明语句时会执行声明操作,而之后再执行到该语句处时会自动跳过。
作用范围:与不加static时的作用范围相同,还是局部可用
销毁:和全局变量一样在main函数的栈帧销毁时一并销毁
全局变量->限制访问原本同级文件夹下的源文件可以用extern关键字互相获取全局变量,但如果用static修饰本地全局变量,那么这个全局变量只能在本文件调用,而其它文件看不到它
全局函数->限制访问原本同级文件夹下的源文件可以用extern关键字声明函数,然后去其它源文件的全局函数中寻找实现方式,但如果用static修饰本地全局函数,那么这个全局函数的实现只能在本文件调用,而其它文件看不到它
C++类和对象成员变量->静态成员 (全局变量)原本声明的成员变量在实例化后,属于由类实例化出来的对象,生命周期与所属对象相同,但在加了static后 ...
归并排序
时间复杂度: O(nlogn)空间复杂度: O(n)稳定性: 稳定实现语言: C/C++
原理思想这里采用的是分治的思想,但与快速排序相反的是,归并排序采用的是先分治再合并。
已知在有额外空间的情况下,合并两个有序数组得到一个新的较长有序数组是很高效的。 所以能不能把一个任意数组分成由左右两个有序数组组成然后合并成有序数组呢?
显然不能,大部分情况并不能分成两个有序数组,但如果在此之前用同样的方法(这里采用递归)事先排序左右两部分呢?大部分情况依然不能,因此这个递归会一直递推下去,最终待排序区间不断缩小,到只剩一个或零个元素,此时就可以将其看为有序数组了,也就是说递归在这里停止,可以一路合并有序数组一路回归上去了
分治这里使用左右指针控制待排序区间(迭代器也行),并采用递归的方式形象地完成分治操作
123456789101112131415161718void _MergeSort(vector<int>& arr,int left,int right,vector<int>&tmp){ //分治 if(le ...
=Linux=一步步自己写一个shell程序
系统:阿里云服务器Linux CentOs 7
编辑器: vim
编译器: gcc (支持C99)
文件本次写的程序较为简单,所以只使用一个源文件
所以在shell中touch一个makefile和一个myshell.c
shell
12touch makefiletouch myshell.c
然后编辑makefile文件
makefile
1234561 myshell:myshell.c gcc -o $@ $^ -std=c99.PHONY:cleanclean: rm -f myshell
头文件本程序因函数较杂,会include较多头文件
myshell.c
12345#include <stdio.h>#include <stdlib.h>#include <string.h>#include <unistd.h>#include <assert.h>
宏定义为了统一修改部分参数,以及使参数更易读,这里使用部分宏定义
myshell. ...
堆排序
背景知识
知道什么是大堆/小堆
掌握如何将数组与完全二叉树的映射关系
掌握向上调整法和向下调整法
大堆/小堆大堆的特性:每一个节点的值都比左右孩子都大,根的值是整个大堆中最大的小堆的特性:每一个节点的值都比左右孩子都小,根的值是整个大堆中最小的
后面以大堆为例
数组映射成完全二叉树任何一个数组可以看成一个完全二叉树,下标0为二叉树的根
而非常方便的是,已知一个节点的下标,可以利用数学关系求出根或孩子的下标
下标关系如下(变量均为下标)
parent = (child-1)/2
left_child = parent*2+1
right_child = parent*2+2
建堆方法向上调整法在已有一个大堆的前提下,把一个新的数据插入到堆的最后一个节点(此时破坏大堆的结构),再一路向上调整,可以重新建堆
123456789101112131415161718template<class T>void adjust_up(vector<T>& arr, int child){ int parent = (child - ...
C++文件操作
注:追求代码简洁,有一致的C++风格,可参阅本篇博客,若追求更高的读写效率,建议参阅C语言篇 但文章还没写
本篇文章主要研究头文件fstream中的函数和类
目前C++文件操作主要有两种流派,一种是声明fstream对象,另一种是分开声明ifstream和ofstream
注意,本文代码为了简洁,都是在展开std命名空间的前提下书写
fstream的使用先写一段示例代码
12345678910111213141516171819202122#include <iostream>#include <fstream>using namespace std;int main(){ fstream f("file.txt", ios::out);//调用构造函数以out模式打开文件file.txt 注:out模式下file.txt 会自动创建 string str = "This is a sentence";//在内存中准备一段字符串 f << str;//将字符串从内存写入文件 f.close();//关 ...
通过设计list类深入理解iterator迭代器
前置博客:从构建一个Date类入门C++类与对象
下面先迅速地搓一个list类
1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859template <class T>//先用模板创建一个节点类struct ListNode{ T _val; ListNode<T>* _next; ListNode<T>* _prev; //提供全缺省的默认构造函数 ListNode(const T& val = T()) :_val(val), _next(nullptr), _prev(nullptr) {}};//用ListNode构造list类template <class T>class list{ typedef ListNode<T> Node;//用typedef简化代码public: list()// ...
vim基础指令集
Vim是一款文本编辑器,下面介绍在vim界面中的常用指令
三种模式:命令模式(Command Mode) 插入模式(Insert Mode 命令行模式(Command-Line Mode)(这里称命令行模式为底行模式)
三者关系如下图
命令模式vim界面中多摁几次ESC就能退出其它模式回到命令模式,在这个模式下可以使用一系列vim快捷键
底行模式tips:不管目前是什么模式,先狂按ESC,回到命令模式,然后输入:进入底行模式,准备开始输命令
命令组成
保存:w->强制保存!w
退出:q->强制退出:!q
保存并退出:wq-.强制保存并退出:!wq
对比:vs +(源文件路径)
插入模式在命令模式下按键盘i进入插入模式,执行正常的文本编辑功能