低代码到底是不是行业毒瘤?一线大厂怎么做的?戳此了解>>> 了解详情
写点什么

Linux 编程基础知识

2019 年 11 月 20 日

Linux编程基础知识

OpsDev 团队从九月中旬启动了“公开课”形式的技术分享活动,由某领域擅长的同学系统性向大家介绍技术要点和细节。第一期公开课由李钢老师开讲,内容为“应用编程基础课”,分为 5 节课,每节课的课程大纲和重点干货我们都会整理成文分享出来供更多的同学一起学习。


前言

本人从事 linux 下 web 编程多年,最近有幸给组内同学做培训,希望能给大家介绍下自己这些年在应用编程方面的经验,今天先给大家介绍下一些编程方面的需要掌握的基础知识。


1 操作系统介绍

先来看一个 unix 系统的架构图:



从内向外,unix 系统架构分为:


1.内核:控制硬件资源,提供应用程序运行的环境


2.系统调用:内核的编程接口


3.shell 和库函数:为应用程序提供编程、运行接口


4.应用程序:我们自己编写的程序


2 系统调用和库函数

应用程序可以调用系统调用和库函数,很多库函数都会调用系统调用,用下面这幅图来展示二者的区别:



上面说过,内核用于控制硬件资源。例如从磁盘上读写文件,相当于需要控制硬盘这个硬件做 IO 操作,这个事情需要内核来做,那如何告诉内核要做这个事情呢?系统调用就是干这个事情的,它是内核暴露出来的一组编程接口,通过调用这个接口来执行内核中的代码。


库函数不是内核代码,是更高一层的功能封装。如我们常用的 printf 函数,我们可以调用这个函数输出内容到显示器上,但控制显示器的输出是内核做的事情,系统调用提供的是 write 方法,printf 相当于封装了 write 这个系统调用,给应用程序提供了一个更加友好的操作方式。


总结下,系统调用相当于内核代码的调用入口,库函数是对应用程序要使用的功能的一层友好的封装。


3 用户态和内核态

程序在运行时会有用户态和内核态的区别,请见下图:



简单一句话,程序执行时,如果执行的是我们编写的应用程序的代码,这些代码就是运行在用户态的;当代码中调用了系统调用后,接下来内核中的代码就会执行,内核中的代码就是运行在内核态的。


4 程序是如何执行的

我们用最经典的 hello world 来说明下程序是如何执行的。


程序源码 hello.c:



首先,我们开发的 hello.c 存储在磁盘上,我们首先编译它,得到可执行文件 hello:



这一步编译,实际上经历了如下处理流程:



当我们运行 hello 程序时,效果如下:



实际执行流程如下:


首先,我们通过键盘输入./hello,shell 读取每个字符到寄存器中,然后存储到主存中:



当我们输入 enter 后,shell 知道我们完成了命令输入,将 hello 这个程序从磁盘加载到主存:



使用 DMA(direct memory access)技术,数据从磁盘直接加载到主存中,避免了通过 CPU 传输。


当代码加载到主存后,CPU 开始执行程序指令,这些指令拷贝 hello, world\n 字符串从内存到寄存器,然后传输到显示设备,显示设备负责显示结果:



5 进程、线程、协程

我们先来看下一个经典的程序在内存中的布局:



1.text 段就是我们的程序代码


2.initialized data 中是我们代码中明确初始化的一些全局变量、静态变量


3.bss 段中放的是代码中没有初始化的全局变量、静态变量


4.heap 是我们程序中动态申请的内存空间,例如调用 malloc,这个空间很大


5.stack 中的空间由程序中的局部变脸和函数调用使用


进程

什么是进程呢?我理解进程就是运行中的程序在操作系统中的一个具象化的表现。


每个进程在内存中都拥有上面那些布局,而且都是独立的,不共享。


线程

那么什么是线程呢?我自己理解,每个线程代表了一个独立的执行流。


举个例子,hello 那个程序中,如果 printf 语句要执行 10 次,那么这 10 次可以一个挨着一个顺序来执行,这是一个执行流;


也可以创建 10 个执行流,每个都执行一次 printf,如果我们有至少 10 个 cpu 核,这样就可以做到 10 个 printf 并行执行。


所以,线程是操作系统调度的最小单元。


同一进程的多线程间,栈空间(stack)是相互独立的,而其它数据是共享的,所以高性能的多线程编程首先要解决的就是锁的问题。


协程

一些现代的编程语言会有这个概念,它又是什么呢?


我理解,协程是一个用户态的概念。


线程是由操作系统内核进行调度的,我们无法干预,协程是用户态程序,相当于应用程序自己进行了调度。


因为它是用户态程序,所以相当于多个协程会运行在一个线程中。


要注意的是,只有内核对线程的调度才能够利用 cpu 的多核资源,让程序做到并行,所以在一个线程中的多个协程,是无法做到并行的。


父子进程间的共享

我们来看一张图:



这张图描述的是当我们在程序中用 open 这个系统调用打开一个文件时,操作系统中维护的相关数据结构,这里最重要的一个说明,就是最左面 process table entry 部分可以理解为是用户态程序中的,其它的 file table entry 和 v-node table entry 是内核中的。


当我们使用 fork 创建新进程后,用户态的内容都会复制一份给子进程,而内核中的部分会保持不变,如下图:



所以,父子进程相当于可以通过相同的文件描述符来共享内核中的数据结构。这个特性,就是未来我们做服务的平滑重启的最重要的一点。


6 结束语

上面这些,都是笔者编程这些年,觉得非常受用的基础知识。正确的认识这些知识,很多问题你都可以自己想明白了。


笔者也是在不断学习中,如果有错误的地方,还望指正,我们共同进步,谢谢!


本文转载自公众号 360 云计算(ID:hulktalk)。


原文链接:


https://mp.weixin.qq.com/s/5XjlxkNwapl_F60sgDNXXw


2019 年 11 月 20 日 15:36645

评论

发布
暂无评论
发现更多内容

产品经理第二课作业

撒.野

产品经理训练营-第二周作业

月亮 😝

抽奖助手:假设你是一个抽奖小程序产品的负责人,列出产品的利益相关方。

三生赤水

第二周作业

z

看西联软件如何拿下四川省 7 成连锁卖场 | AWS 精选案例

亚马逊云科技 (Amazon Web Services)

京东发布《未来科技趋势白皮书》,101页详解5大关键技术

京东数科风险算法与技术

产品训练营作业:2、产品意思和产品思维(1)

Geek_06d2e5

自从上了K8S,项目更新都不带停机的!

Java架构师迁哥

第二周作业

岛乾坤

删库跑路被判入狱,明知不可为而为之

李忠良

28天写作

产品课程-第二周作业

狗三

SpringBoot项目就连创建目录都让人抓狂

互联网架构师小马

二手车平台app利益相关方分析

戎帅

产品经理训练营作业第2周

黑小白白白

极客大学产品经理训练营

产品训练营第二周作业-利益相关者

jpcr987i

产品经理训练营第 0 期 - 第二周作业

🍑

极客大学产品经理训练营

极客时间产品经理训练营第 2 次作业

待注册

产品训练营 第二周作业

万顷湖天碧

产品训练营

产品经理训练营 Week2 学习心得

Mai

产品训练营-第二周学习总结

Trigger

极客时间 极客大学产品经理训练营 产品训练营

作业 - 第二章 产品思维和产品意识

hao hao

笔记1-2

🍑

极客大学产品经理训练营

极客大学架构师训练营成果索引

晴空万里

架构师训练营第2期

产品作业2

Tomz

产品经理训练营

产品训练营第二周作业

朱航

产品经理第 0 期训练营第二周作业提交

Krystal

产品经理训练营 - 第二次作业

羽室

第二周总结

岛乾坤

第2章:产品思维作业

让时间说真话

产品经理

新浪微博利益相关方分析

🙈🙈🙈

极客大学产品经理训练营

科技创投媒体36Kr的容器化之路

RancherLabs

2021 ThoughtWorks 技术雷达峰会

2021 ThoughtWorks 技术雷达峰会

Linux编程基础知识-InfoQ