【Linux教程】Linux系统零基础编程入门,想当大神?这些你都要学
✍ 文件和文件系统
文件是Linux系统中最重要的抽象,大多数情况下你可以把linux系统中的任何东西都理解为文件,很多的交互操作其实都是通过文件的读写来实现的。
文件描述符
在Linux内核中,文件是用一个整数来表示的,称为 文件描述符,通俗的来说,你可以理解它是文件的id(唯一标识符)
普通文件
普通文件就是字节流组织的数据。
文件并不是通过和文件名关联来实现的,而是通过关联索引节点来实现的,文件节点拥有文件系统为普通文件分配的唯一整数值(ino),并且存放着一些文件的相关元数据。
目录与链接
正常情况下文件是通过文件名来打开的。
目录是可读名称到索引编号之间的映射,名称和索引节点之间的配对称为链接。
可以把目录看做普通文件,只是它包含着文件名称到索引节点的映射(链接)
✍ 进程
进程是仅次于文件的抽象概念,简单的理解,进程就是正在执行的目标代码,活动的,正在运行的程序。不过在复杂情况下,进程还会包含着各种各样的数据,资源,状态甚至虚拟计算机。
你可以这么理解进程:它是竞争计算机资源的基本单位。
进程、程序与线程
程序
程序,简单的来说就是存在磁盘上的二进制文件,是可以内核所执行的代码
进程
当一个用户启动一个程序,将会在内存中开启一块空间,这就创造了一个进程,一个进程包含一个独一无二的PID,和执行者的权限属性参数,以及程序所需代码与相关的资料。
进程是系统分配资源的基本单位。
一个进程可以衍生出其他的子进程,子进程的相关权限将会沿用父进程的相关权限。
线程
每个进程包含一个或多个线程,线程是进程内的活动单元,是负责执行代码和管理进程运行状态的抽象。
线程是独立运行和调度的基本单位。
进程的层次结构(父进程与子进程)
在进程执行的过程中可能会衍生出其他的进程,称之为子进程,子进程拥有一个指明其父进程PID的PPID。子进程可以继承父进程的环境变量和权限参数。
于是,linux系统中就诞生了进程的层次结构——进程树。
进程树的根是第一个进程(init进程)。
过程调用的流程: fork & exec
一个进程生成子进程的过程是,系统首先复制(fork)一份父进程,生成一个暂存进程,这个暂存进程和父进程的区别是pid不一样,而且拥有一个ppid,这时候系统再去执行(exec)这个暂存进程,让他加载实际要运行的程序,最终成为一个子进程的存在。
进程的结束
当一个进程终止时,并不会立即从系统中删除,内核将在内存中保存该进程的部分内容,允许父进程查询其状态(这个被称为等待终止进程)。
当父进程确定子进程已经终止,该子进程将会被彻底删除。
但是如果一个子进程已经终止,但父进程却不知道它的状态,这个进程将会成为 僵尸进程
服务与进程
简单的说服务(daemon)就是常驻内存的进程,通常服务会在开机时通过init.d中的一段脚本被启动。
进程通信
进程通信的几种基本方式:管道,信号量,消息队列,共享内存,快速用户控件互斥。
✍ 程序,进程和线程
现在我们再次详细的讨论这三个概念
程序(program)
程序是指编译过的、可执行的二进制代码,保存在储存介质上,不运行。
进程(process)
进程是指正在运行的程序。
进程包括了很多资源,拥有自己独立的内存空间。
线程
线程是进程内的活动单元。
包括自己的虚拟储存器,如栈、进程状态如寄存器,以及指令指针。
在单线程的进程中,线程即进程。而在多线程的进程中,多个线程将会共享同一个内存地址空间
✍ 运行一个进程
创建一个进程,在unix系统中被分为了两个流程。
● 把程序载入内存并执行程序映像的操作:exec
● 创建一个新进程:fork
exec
最简单的exec系统调用函数:execl()
● 函数原型:
int execl(const char * path,const chr * arg,...)
execl()调用将会把path所指的路径的映像载入内存,替换当前进程的映像。
参数arg是以第一个参数,参数内容是可变的,但最后必须以NULL结尾。
● 举例:
int ret; ret = execl("/bin/vi","vi",NULL); if (ret == -1) { perror("execl"); }
上面的代码将会通过/bin/vi替换当前运行的程序
注意这里的第一个参数vi,是unix系统的默认惯例,当创建、执行进程时,shell会把路径中的最后部分放入新进程的第一个参数,这样可以使得进程解析出二进制映像文件的名字。
int ret; ret = execl("/bin/vi","vi","/home/mark/a.txt",NULL); if (ret == -1) { perror("execl"); }
上面的代码是一个非常有代表性的操作,这相当于你在终端执行以下命令:
vi /home/mark/a.txt
● 返回值:
正常情况下其实execl()不会返回,调用成功后会跳转到新的程序入口点。
成功的execl()调用,将改变地址空间和进程映像,还改变了很多进程的其他属性。
不过进程的PID,PPID,优先级等参数将会被保留下来,甚至会保留下所打开的文件描述符(这就意味着它可以访问所有这些原本进程打开的文件)。
失败后将会返回-1,并更新errno。
● 其他exec系函数
略,使用时查找
fork
通过fork()系统调用,可以创建一个和当前进程映像一模一样的子进程。
● 函数原型
pid_t fork(void)
调用成功后,会创建一个新的进程(子进程),这两个进程都会继续运行。
● 返回值
如果调用成功,
父进程中,fork()会返回子进程的pid,在子进程中返回0;
如果失败,返回-1,并更新errno,不会创建子进程。
● 举例
我们看下面这段代码
#include <unistd.h> #include <stdio.h> int main () { pid_t fpid; //fpid表示fork函数返回的值 int count=0; printf("this is a process\n"); fpid=fork(); if (fpid < 0) printf("error in fork!"); else if (fpid == 0) { printf("i am the child process, my process id is %d\n",getpid()); printf("我是爹的儿子\n"); count++; } else { printf("i am the parent process, my process id is %d\n",getpid()); printf("我是孩子他爹\n"); count++; } printf("统计结果是: %d\n",count); return 0; }
这段代码的运行结果比较神奇,是这样的:
this is a process i am the parent process, my process id is 21448 我是孩子他爹 统计结果是: 1 i am the child process, my process id is 21449 我是爹的儿子 统计结果是: 1
在执行了fork()之后,这个程序就拥有了两个进程,父进程和子进程分别往下继续执行代码,进入了不同的if分支。
如何理解pid在父子进程中不同?
其实就相当于链表,进程形成了链表,父进程的pid指向了子进程的pid,因为子进程没有子进程,所以pid为0。
● 写时复制
传统的fork机制是,调用fork时,内核会复制所有的内部数据结构,复制进程的页表项,然后把父进程的地址空间按页复制给子进程(非常耗时)。
现代的fork机制采用了一种惰性算法的优化策略。
为了避免复制时系统开销,就尽可能的减少“复制”操作,当多个进程需要读取他们自己那部分资源的副本时,并不复制多个副本出来,而是为每个进程设定一个文件指针,让它们读取同一个实际文件。
显然这样的方式会在写入时产生冲突(类似并发),于是当某个进程想要修改自己的那个副本时,再去复制该资源,(只有写入时才复制,所以叫写时复制)这样就减少了复制的频率。
联合实例
在程序中创建一个子进程,打开另一个应用。
pid_t pid; pid = fork(); if (pid == -1) perror("fork"); //子进程 if (!pid) { const char * args[] = {"windlass",NULL}; int ret; // 参数以数组方式传入 ret = execv("/bin/windlass",args); if (ret == -1) { perror("execv"); exit(EXIT_FAILURE); } }
上面的程序创建了一个子进程,并且使子进程运行了/bin/windlas程序。
✍ 终止进程
exit()
● 函数原型
void exit (int status)
该函数用于终止当前的进程,参数status只用于标识进程的退出状态,这个值将会被传送给当前进程的父进程用于判断。
还有一些其他的终止调用函数,在此不赘述。
如果你也很想学编程,从零基础开始,一起来学编程,可以来我的零基础编程学习基地【点击进入】!
还有(源码,零基础教程,项目实战教学视频)!带你入个门还是简简单单啦~
涉及:游戏开发、课程设计、常用软件开发、编程基础知识、黑客等等...
【Linux教程】Linux系统零基础编程入门,想当大神?这些你都要学的更多相关文章
- 【Python教程】《零基础入门学习Python》(小甲鱼)
[Python教程]<零基础入门学习Python>(小甲鱼) 讲解通俗易懂,诙谐. 哈哈哈. https://www.bilibili.com/video/av27789609
- IM开发者的零基础通信技术入门(二):通信交换技术的百年发展史(下)
1.系列文章引言 1.1 适合谁来阅读? 本系列文章尽量使用最浅显易懂的文字.图片来组织内容,力求通信技术零基础的人群也能看懂.但个人建议,至少稍微了解过网络通信方面的知识后再看,会更有收获.如果您大 ...
- IM开发者的零基础通信技术入门(一):通信交换技术的百年发展史(上)
[来源申明]本文原文来自:微信公众号“鲜枣课堂”,官方网站:xzclass.com,原题为:<通信交换的百年沧桑(上)>,本文引用时已征得原作者同意.为了更好的内容呈现,即时通讯网在收录时 ...
- IM开发者的零基础通信技术入门(三):国人通信方式的百年变迁
[来源申明]本文原文来自:微信公众号“鲜枣课堂”,官方网站:xzclass.com,原题为:<中国通信的百年沉浮>,本文引用时已征得原作者同意.为了更好的内容呈现,即时通讯网在收录时内容有 ...
- salesforce 零基础开发入门学习(一)Salesforce功能介绍,IDE配置以及资源下载
目前国内已经有很多公司做salesforce,但是国内相关的资料确是少之又少.上个月末跳槽去了新公司,主要做的就是salesforce,不过当时想要看一些相关资料确实比较难.为了避免想要零基础学习的人 ...
- 序言 - PHP零基础快速入门
我为什么要写<PHP零基础快速入门>? 原因: PHP 真心简单,适合零基础的人快速入门掌握,身边的人学习一两周上手开发的比比皆是: 市面上的文章或书籍对初学者并不友好,多半枯燥乏味,我相 ...
- 零基础快速入门web学习路线(含视频教程)
下面小编专门为广大web学习爱好者汇总了一条完整的自学线路:零基础快速入门web学习路线(含视频教程)(绝对纯干货)适合初学者的最新WEB前端学习路线汇总! 在当下来说web前端开发工程师可谓是高福利 ...
- 普通程序员转型AI免费教程整合,零基础也可自学
普通程序员转型AI免费教程整合,零基础也可自学 本文告诉通过什么样的顺序进行学习以及在哪儿可以找到他们.可以通过自学的方式掌握机器学习科学家的基础技能,并在论文.工作甚至日常生活中快速应用. 可以先看 ...
- C++零基础到入门
(1)C语言概述 (2)编写.运行一个简单的C语言程序 (3)数据类型 (4)运算符和表达式 如果你对C语言一窍不通,那你就好好看这篇文章,我会力争让你真正的做到从零基础到入门,同时这篇文章会让你基本 ...
随机推荐
- 4.FFMPEG-AVFrame
在ffmpeg中,解码前的数据结构体为AVPacket(参考:3.AVPacket使用),而解码后的数据为AVFrame(视频的YUV, RGB, 音频的PCM,数据量更大) 1.AVFrame介绍 ...
- 5.AVStream和AVCodecParameters
AVStream和AVCodecParameters 说明: AVStream 结构表示当前媒体流的上下文,着重于所有媒体流共有的属性(并且是在程序运行时才能确定其值)和关联其他结构的字段. 其中co ...
- 为ASP_NET应用程序启用SQL缓存
步骤一: sql数据库必须开启ServiceBroker服务,首先检测是否已经启用ServiceBroker,检测方法: SELECT DATABASEPROPERTYEX('dbName','IsB ...
- Java基础之HashMap原理分析(put、get、resize)
在分析HashMap之前,先看下图,理解一下HashMap的结构 我手画了一个图,简单描述一下HashMap的结构,数组+链表构成一个HashMap,当我们调用put方法的时候增加一个新的 key-v ...
- 第11课 - enum, sizeof, typedef 分析
第11课 - enum, sizeof, typedef 分析 1. enum介绍 (1)enum是C语言中的一种自定义类型,和struct.union地位相同,格式如下: // enum每个值的最后 ...
- istio 常见的 10 个异常
总结使用 istio 常见的10个异常: Service 端口命名约束 流控规则下发顺序问题 请求中断分析 sidecar 和 user container 启动顺序 Ingress Gateway ...
- 我的Python自学之路-001 列表的知识
#_date_:2020/9/11 '''列表和字典是python中用的最多的数据类型 假如要存储一个班级的人名,需要怎么做?有这么几种方法:1.定义很多个变量: name0 = 'wucaho' n ...
- 基于Prometheus网关的监控完整实现参考
prometheus 是一个非常好的监控组件,尤其是其与grafana配合之后,更是如虎添翼.而prometheus的监控有两种实现方式.1. server端主动拉取应用监控数据:2. 主动推送监控数 ...
- 浅入webpack
webpack.base.conf---webpack基础配置: f利用各种文件对项目中的文件进行处理 利用loader,preloader对工程文件进行处理,输出新的工程文件(options中对文件 ...
- Oracle添加键值对盲注
前言 遇到一种注入点,存在于POST参数中,却不能用sqlmap扫出: 分析 request参数格式: %24Q_value1=test1&orderCol=&order=+ASC+& ...