[IT鹅C/C++系列课程]靓仔我想学编程为什么给我讲操作系统?
Posted IT鹅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[IT鹅C/C++系列课程]靓仔我想学编程为什么给我讲操作系统?相关的知识,希望对你有一定的参考价值。
Day01:
让我们重拾对梦中情人C和C++的热爱
[IT鹅C/C++系列课程]操作系统基础Operating System Fundamentals Course
一部“逆天”的“爽文”编程教程
BILIBILI IT鹅 BILIBILI@IT鹅
课程介绍:
[C/C++系列课程]操作系统基础Operating System Fundamentals Course
本课程使用了ICS与SP教学模式,用通俗易懂的语言讲解枯燥无味的C/C++,本课程将会从硬件、操作系统和编译系统对应用程序性能与正确性影响。SP是一门系统编程课程,当我们具备基本编码技能后,课程在后期从系统编程(Linux),进程、网络编程等方面做简易介绍。
前言:
文章多有不尽人意之处,希望学者朋友们能进行勘误建议,感激万分!
主流操作系统OS
主流操作系统包括Windows,MacOS,android,Linux等,严格来讲Android系统属于Linux系统的分支,Android系统基于Linux系统内核,主流的Ubunutu Debian发行版本也都是基于Linux Kernel,但是不同版本的Linux发行版本有不同的软件源,这也是为什么Linux发行版本良莠不一的原因之一。但是Linux系统拥有一个社区,全世界的开发者都可以向kernl.org提交自己对内核的贡献,报送Linux系统相关高位漏洞,Windows与MacOS是依据Unix设计的操作系统。
🤔️[疑问1]
Android系统与Linux系统关系?
Android是在Linux内核基础之上,Linux提供核心服务:安全、内存管理、进程管理、网络和驱动模型等。
有些老师可能会给你讲,Android系统属于外壳shell,而不是内核kernel。
什么是shell?同学们也许会在某某逆天黑客小说里见过这个词语,黑客随手就是一个shell,中文译名壳,指的是人类于机器交互的命令解释程序,简单来讲,windows系统中,cmd属于shell,Linux上的bash属于shell,MacOS上的Terminal终端,bash又是什么(再简单来讲所谓黑客在电脑黑窗口里输入的装逼命令,下图是终端的截图
简单的装逼命令:
echo 靓仔专用shell
echo 靓仔你好
🤔 这也是编程??? 准确的来说,这就是shell能够理解的语言。
什么⬆️ 这就是shell?!
从曼切斯特机器时代到迷你计算机时代
大型机器时代
最早的计算机是没有任何形式的操作系统的大型机。1949年。最初的机器是曼切斯特1型商用计算机诞生,这是最早的存储程序计算机之一,每个用户在预定的时间段内单独使用机器,并带着程序和数据到达计算机,通常是打孔纸卡和磁带或纸带。该程序将被加载到机器中,并且机器将被设置为工作,直到程序完成或崩溃。程序通常可以通过控制面板使用转盘、拨动开关和面板灯进行调试。
后来,机器引入帮助程序输入输出工作的代码库,什么是代码库(codebase)
一般指的是人工编写的源代码文件,然而每次机器只能执行一次任务。
迷你电脑时代
UNIX操作系统是在 1960 年由AT&T公司的贝尔实验室开发出来的,这是一个由C语言编写的系统,那么UNIX是如何工作的,本文不细致介绍。但是你需要了解到,UNIX操作系统是一个划时代的产物,由于C语言具备可移植的特性,所以UNIX可以进行再不同硬件设备上进行移植。
(补充一下C语言的历史:从前文学习了C语言的基本概况让我们重拾对梦中情人C和C++的热爱)
C语言于1969年至1973年间,为了移植与开发UNIX操作系统,由丹尼斯·里奇与肯·汤普逊,以B语言为基础,在贝尔实验室设计、开发出来。
Apple与DOS之后的时代
微型处理器的发展使计算机的应用普及至中小企业及个人爱好者。而计算机的普及又推动了硬件组件公共接口的发展。早期计算机中主要的操作系统是8080/8085/Z-80 CPU用的CP/M-80。这些计算机在ROM(只读存储器)都有一个小小的启动程序,可以把操作系统从磁盘装载到内存。IBM-PC系列的Bios是这一思想的延伸。自1981年第一台IBM-PC诞生以来,BIOS的功能得到不断地增强。
回到本文重心,此时我们又有**【疑问2】🤔️**
最初的操作系统如何移植到计算机上面的?
关于操作系统历史知识请参考:RedHat代码英雄 Linux中国
现代操作系统
操作系统精髓与设计原理
操作系统纲要:
内核:
内核系统架构:
Exokernel外核心 **Hybrid Kernel 混合核心(Monolithic kernel&Micro Kernel)微内核(Microkernel,μ-kernel)宏内核(Monolithic kernel)单一内核(Unikernel) **
内核组件
驱动程序(driver) 可加载核心模块LKM(Loadable kernel module)微内核(Micro Kernel)用户空间(User Space)
概念:
上下文切换(content Switch):多任务处理multitasking 中断处理 Interrupt tasking 用户态与内核台切换user mode switch to kernel mode
中断:interrupt,顾名思义,当我们的计算机硬件或者OS接收到某个特殊的信号的时候,计算机会立刻停手中的工作,去做另外一件事情,完成任务后,再继续做手上的任务。好比,当你在学习的时候,好兄弟叫你出去打羽毛球,打完羽毛球后,你又要开始学习之旅,这样的定义并不专业,但是我们可以这样简易理解中断。
专业一点(重点):
硬件中断(Hardware Interrupt)
软件中断(Software Interrupt)
由于软中断指令通常要运行一个切换CPU至内核态(Kernel Mode/Ring 0)的子例程,它常被用作实现系统调用(System call)
进程间通信
IPC,Inter-Process Communication),指至少两个进程或线程间传送数据或信号的一些技术或方法。进程是计算机系统分配资源的最小单位(严格说来是线程).每个进程都有自己的一部分独立的系统资源,彼此是隔离的。为了能使不同的进程互相访问资源并进行协调工作,才有了进程间通信。
IPC通信应用:Web服务器,我们在通过网页使用进程通信来共享web文件(html)
进程(process)
我想命令计算机,这个时候操作系统就会产生进程,同一个程序可以产生多个进程(一对多的关系),进程运行效率取决于CPU运行效率。
划重点:进程与线程的区别:进程是计算机管理运进程序的一种方式,一个进程下可包含一个或者多个线程。线程可以理解为子进程。线程是进程的子集。
进程控制块(Process Control Block,PCB)
操作系统核心的数据结构,主要是为了表示进程状态,it included process status,it can be new, ready, running, waiting and blocked and so on。
(不知道为什么这里就飙洋文了,同学们理解下,计算机用洋文讲的更明白)CPU寄存器(累加器accumulator)变址器,堆栈指针(stack pointer)
靓仔等等,什么是Stack Pointer,这是一个似曾相识的名字,没错堆栈指针很重要!那么下面就简单介绍下堆栈指针。(枯燥乏味的堆栈指针以后能经常用上)
计算机中重要的ADT:
ADT:Abstract Data Type抽象数据类型
本小节鹅带你简单了解堆栈
堆栈(Stack),俗称栈,拼音字母(zhan),客栈的“栈”。
堆栈两种基本操作:(压栈,push)与(出栈,pop)
特点: 先进后出,后进先出。
C语言中我们用一个叫做链表(linked list)的数据结构来描述,请观察下图并描述特点
堆栈可以用数组和链表两种方式实现。
下面这段程序来自高一凡《数据结构》算法实现及解析2004年10月第2版
存储结构:
#define STACK_INIT_SIZE 10 /* 存储空间初始分配量 */
#define STACK_INCREMENT 2 /* 存储空间分配增量 */
typedef struct SqStack
SElemType *base; /* 在栈构造之前和销毁之后,base的值为NULL */
SElemType *top; /* 栈顶指针 */
int stacksize; /* 当前已分配的存储空间,以元素为单位 */
SqStack; /* 顺序栈 */
基本操作
/* bo3-1.c 顺序栈(存储结构由c3-1.h定义)的基本操作(9个) */
void InitStack(SqStack *S)
/* 构造一个空栈S */
(*S).base=(SElemType *)malloc(STACK_INIT_SIZE*sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top=(*S).base;
(*S).stacksize=STACK_INIT_SIZE;
void DestroyStack(SqStack *S)
/* 销毁栈S,S不再存在 */
free((*S).base);
(*S).base=NULL;
(*S).top=NULL;
(*S).stacksize=0;
void ClearStack(SqStack *S)
/* 把S置为空栈 */
(*S).top=(*S).base;
Status StackEmpty(SqStack S)
/* 若栈S为空栈,则返回TRUE,否则返回FALSE */
if(S.top==S.base)
return TRUE;
else
return FALSE;
int StackLength(SqStack S)
/* 返回S的元素个数,即栈的长度 */
return S.top-S.base;
Status GetTop(SqStack S,SElemType *e)
/* 若栈不空,则用e返回S的栈顶元素,并返回OK;否则返回ERROR */
if(S.top>S.base)
*e=*(S.top-1);
return OK;
else
return ERROR;
void Push(SqStack *S,SElemType e)
/* 插入元素e为新的栈顶元素 */
if((*S).top-(*S).base>=(*S).stacksize) /* 栈满,追加存储空间 */
(*S).base=(SElemType *)realloc((*S).base,((*S).stacksize+STACK_INCREMENT)*sizeof(SElemType));
if(!(*S).base)
exit(OVERFLOW); /* 存储分配失败 */
(*S).top=(*S).base+(*S).stacksize;
(*S).stacksize+=STACK_INCREMENT;
*((*S).top)++=e;
Status Pop(SqStack *S,SElemType *e)
/* 若栈不空,则删除S的栈顶元素,用e返回其值,并返回OK;否则返回ERROR */
if((*S).top==(*S).base)
return ERROR;
*e=*--(*S).top;
return OK;
void StackTraverse(SqStack S,void(*visit)(SElemType))
/* 从栈底到栈顶依次对栈中每个元素调用函数visit() */
while(S.top>S.base)
visit(*S.base++);
printf("\\n");
链表基本操作
/* bo2-8.c 不带头结点的单链表(存储结构由c2-2.h定义)的部分基本操作(9个) */
#define DestroyList ClearList /* DestroyList()和ClearList()的操作是一样的 */
void InitList(LinkList *L)
/* 操作结果:构造一个空的线性表L */
*L=NULL; /* 指针为空 */
void ClearList(LinkList *L)
/* 初始条件:线性表L已存在。操作结果:将L重置为空表 */
LinkList p;
while(*L) /* L不空 */
p=*L; /* p指向首元结点 */
*L=(*L)->next; /* L指向第2个结点(新首元结点) */
free(p); /* 释放首元结点 */
Status ListEmpty(LinkList L)
/* 初始条件:线性表L已存在。操作结果:若L为空表,则返回TRUE,否则返回FALSE */
if(L)
return FALSE;
else
return TRUE;
int ListLength(LinkList L)
/* 初始条件:线性表L已存在。操作结果:返回L中数据元素个数 */
int i=0;
LinkList p=L;
while(p) /* p指向结点(没到表尾) */
p=p->next; /* p指向下一个结点 */
i++;
return i;
Status GetElem(LinkList L,int i,ElemType *e)
/* L为不带头结点的单链表的头指针。当第i个元素存在时,其值赋给e并返回OK,否则返回ERROR */
int j=1;
LinkList p=L;
if(i<1) /* i值不合法 */
return ERROR;
while(j<i&&p) /* 没到第i个元素,也没到表尾 */
j++;
p=p->next;
if(j==i) /* 存在第i个元素 */
*e=p->data;
return OK;
else
return ERROR;
int LocateElem(LinkList L,ElemType e,Status(*compare)(ElemType,ElemType))
/* 初始条件:线性表L已存在,compare()是数据元素判定函数(满足为1,否则为0) */
/* 操作结果:返回L中第1个与e满足关系compare()的数据元素的位序。 */
/* 若这样的数据元素不存在,则返回值为0 */
int i=0;
LinkList p=L;
while(p)
i++;
if(compare(p->data,e)) /* 找到这样的数据元素 */
return i;
p=p->next;
return 0;
Status ListInsert(LinkList *L,int i,ElemType e)
/* 在不带头结点的单链线性表L中第i个位置之前插入元素e */
int j=1;
LinkList p=*L,s;
if(i<1) /* i值不合法 */
return ERROR;
s=(LinkList)malloc(sizeof(struct LNode)); /* 生成新结点 */
s->data=e; /* 给s的data域赋值 */
if(i==1) /* 插在表头 */
s->next=*L;
*L=s; /* 改变L */
else
/* 插在表的其余处 */
while(p&&j<i-1) /* 寻找第i-1个结点 */
p=p->next;
j++;
if(!p) /* i大于表长+1 */
return ERROR;
s->next=p->next;
p->next=s;
return OK;
Status ListDelete(LinkList *L,int i,ElemType *e)
/* 在不带头结点的单链线性表L中,删除第i个元素,并由e返回其值 */
int j=1;
LinkList p=*L,q;
if(i==1) /* 删除第1个结点 */
*L=p->next; /* L由第2个结点开始 */
*e=p->data;
free(p); /* 删除并释放第1个结点 */
else
while(p->next&&j<i-1) /* 寻找第i个结点,并令p指向其前驱 */
p=p->next;
j++;
if(!p->next||j>i-1) /* 删除位置不合理 */
return ERROR;
q=p->next; /* 删除并释放结点 */
p->next=q->next;
*e=q->data;
free(q);
return OK;
void ListTraverse(LinkList L,void(*vi)(ElemType))
/* 初始条件:线性表L已存在。操作结果:依次对L的每个数据元素调用函数vi() */
LinkList p=L;
while(p)
vi(p->data);
p=p->next;
printf("\\n");
回到进程管理的介绍。
实时操作系统(Real-time operating system, RTOS)
实时操作系统与一般的操作系统相比,最大的特色就是“实时性”.如果有一个任务需要执行,实时操作系统会马上(在较短时间内)执行该任务,不会有较长的延时。这种特性保证了各个任务的及时执行。
线程:
线程(thread)是操作系统能够进行运算调度的最小单位。大部分情况下,它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。在Unix System V及SunOS中也被称为轻量进程(lightweight processes),但轻量进程更多指内核线程(kernel thread),而把用户线程(user thread)称为线程。
C++11标准创建线程:
(这里同学们不太了解什么是C++11的,可以去看我的B站视频,或者前一篇文章)
C++11标准线程简介:
2011年8月12日,国际标准化组织(ISO)发布的ISO C++标准,C++11首次引入了C++标准线程,Windows平台运行的VS2012和Linux平台运行的g++4.7,都完美支持C++11线程。
头文件是thread
C++11创建线程实现原型
std::thread::thread(Function&& f, Args&&... args);
等待线程结束:
std::thread::join();
脱离线程控制:
std::thread::detach();
交换线程:
std::thread::swap(thread& other);
C++11相关函数:
创建线程:
int thrd_create(thrd_t *thr, thrd_start_t func, void *arg);
结束本线程:
_Noreturn void thrd_exit( int res );
等待线程运行完毕:
int thrd_join(thrd_t thr, int *res);
返回当前线程的线程标识符:
thrd_t thrd_current();
补(tu)充(cao):Java线程(Java就是名词多)
1.Thread/Runnable的run()方法运行完毕终止。
2.使用Future类的cancel()方法调用。
3.调用线程池的shutdown()和shutdownNow()的方法
4.守护线程会在非守护线程都结束时自动终止。
分时系统
分时系统(time-sharing)是计算机科学中对资源的一种共享方式,利用多道程序与多任务处理使多个用户可以同时使用一台计算机。
本系列课程遵循 署名-非商业性使用 3.0 中国大陆 (CC BY-NC 3.0 CN)
转载请标明 CSDN @IT鹅
写在最后的话:
相信同学们上完本次课后,相信你学习了许多奇奇怪怪的名词,也有更多的疑了,这是正常的,因为本节课将操作系统梳理了一遍。那么你的脑海里是否有对计算机学习的热情吗,那么你是否对OS有新的看法了吗,每个人心中都有自己的答案。
⛽️⛽️⛽️(被迫走上流量之路的企鹅~~~)靓仔点个关注➕再走⛽️⛽️⛽️
![](https://image.cha138.com/20220518/1d275ba3f62c4b27ac185bf61f974d19.jpg)
![](https://image.cha138.com/20220518/4cb2c103ff304f1e9bf7a0aa1149c7b9.jpg)
以上是关于[IT鹅C/C++系列课程]靓仔我想学编程为什么给我讲操作系统?的主要内容,如果未能解决你的问题,请参考以下文章
我想学编程,算是兴趣吧。先从C开始还是JAVA,需要用到啥软件,最好是能给网址、里面软件是现在还