Linux系统编程:step1

2023-10-12 15:30
文章标签 linux 系统 编程 step1

本文主要是介绍Linux系统编程:step1,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在这里插入图片描述

一、程序和进程

1、程序和进程
(1)程序:二进制文件,占用的磁盘空间(未运行的,躺在磁盘中)
(2)进程:一个启动的程序(启动之后,程序就和磁盘没有关系了),所有的数据都在内存中,需要占用更多的系统资源(CPU,物理内存),例如:一个剧本(未拍摄,那可以看成程序),要把这个剧本的内容呈现出来(那就是进程),需要演员、道具,场地等(也就是电脑中的系统资源)。需要各个系统资源之间交互。
2、并发和并行
(1)并发:并不是某一个时间点的概念,是一个时间段的概念,常说的高并发服务器,说的是在一短时间内,处理的请求数(例如:1秒内处理的请求个数)。
在这里插入图片描述
例如:一个咖啡机(一个CPU),有100个人去打咖啡,1分钟只能打一杯咖啡,我们需要在1分钟之内让所有的人都能取到咖啡,那么采用的算法就是每人有0.6秒的时间取咖啡,虽然没打满,但是取到了咖啡,只有按照同样的方法进行下去,这就是一个高并发的例子。人相当于请求。
cpu在某一时间点只能处理一个进程,为了能并发处理,CPU会把一个时间段切割成一系列的时间碎片,分给不同的进程使用(有点像时分通信),一句话就是切割时间。
(2)并行
在这里插入图片描述
上图所示,由一个咖啡机变成了两台,也就是增加了一个CPU,用户看到的是并发量变大了,实际上是增加了处理器。例如:淘宝后台服务器提供服务,是通过许多的服务器进行并行提供服务。
小结:每个进程只能在某一时间段获取CPU,所有的进程都是轮循的获取CPU,一个进程不会独占CPU。
3、pcb
进程控制块(process control block)
作用:存在于内核当中,用来维护进程的相关信息,Linux内核PCB是task_struct结构体,也就是一个类型,里面有需要保存的信息(与C++里面面向对象编程如出一辙)。
在这里插入图片描述
重点部分:

  • 进程id(系统中每个进程都有一个进程id(相当于每个人的身份证号),C语言中用pid_t(_t看到这个就表示通过了typedef进行了类型定义)类型表示)
  • 进程的状态:就绪、运行、挂起、停止和初始状态
  • 进程切换需要保存和恢复的一些CPU寄存器(CPU下有很多程序,由于并发执行,所以当一个进程执行到一半的时候,而CPU需要去执行其他进程,那么前一个进程需要保存到寄存器中,保存状态,以用于后面的继续执行)
  • 描述虚拟地址空间:虚拟内存通过MMU映射到物理内存
  • 描述控制终端的信息:因为运行一个进程之后,需要将信息打印到终端。
  • 当前工作目录:在shell进程中,可以通过指令将工作工作目录打印出来
  • umask:每一个进程都有这个,
  • 文件描述符表
  • 和信号相关的信息
  • 用户id和组id
    在这里插入图片描述
  • 会话(session)(会话就是多个进程组组成)和进程组(将多个进程放到一起就组成了一个进程组,例如:一个家庭就是进程组,每个成员就是一个进程);也就是进程组成进程组,进程组组成会话(会话相当于一个村,有多个家庭组成)
  • 进程可以使用的资源上限(resource limit)
    在这里插入图片描述
    以上信息都是保存在进程控制块(PCB)中的,每启动一个进程,都会在内核中的PCB中有记录。
    4、进程的五种状态
    在这里插入图片描述
    初始态:一瞬间的事(怀孕):时间太短,杀死不了(也就是不能直接到终止态)
    重要的状态:就绪态、运行态和挂起态。
  • 就绪态:CPU中进程时分复用CPU,所以进程之间就是竞争关系,例如:一个进程1运行了,那就要去抢CPU的资源了,等待CPU分配并发时间段,这种等待的状态就是就绪态。(感觉自己准备好了,就缺一个机会)
  • 运行态:进程1占用了CPU,可以运行了(人生巅峰,准备好且发挥能力),所以就绪态与运行态区别就是有无CPU。
  • 挂起态:sleep()函数就是让进程睡几秒钟,当睡醒了之后就条件满足可以继续执行。但是,睡醒了不能直接去进入运行态,还要去就绪态去抢CPU,不能插队,睡了一觉,就要老老实实去排队。
    终止态:kill -9 pid

二、进程控制(关键)

进程控制:讲的就是如何建立进程
程序a.out 编程进程,去shell进程中执行 ./a.out 变为子进程
在这里插入图片描述
Q:如何让一个父进程创建一个子进程?
A:int fork(void)
fork(叉子),子进程相当于父进程的一个拷贝,也就是子进程和父进程地址空间一样,也就是上图中除内核的其他部分完全一样。也就是用户区一样。但是内核区不一样,因为内核区中保存了PCB,而PCB中中保存的进程id是不一样的,所以,子、父进程不同的就是进程id不一样。
fork不同之处:有两个返回值,一个进程变为两个进程之后,因为拷贝,两个进程的地址空间是一样的,数据完全一样,在代码段.text中,父子进程都有一个fork,所以都有一个返回值,父进程就返回子进程的一个id,子进程就返回0,所以就有了两个返回值。
在这里插入图片描述
上图所示,父进程中fork之后,其实就拷贝了拥有相同代码的子进程(右边),但是是在父进程中fork的所以pid得到的是子进程的id,而在子进程中,由于没有fork,所以返回的pid是0,以此区分子进程和父进程。也就是返回值是由不同的进程return出来的,拷贝之后就有两个return了。
问题:
Q1:fork函数的返回值 A1:两个,pid>0 父进程的返回值,pid == 0, 子进程的返回值
Q2:子进程创建成功后,代码的执行位置?
A2:正如上面所示,子进程从非灰色部分开始执行,而父进程从头到尾执行。父进程执行到了那,子进程就从那开始执行。
Q3:父子进程的执行顺序?
A3:不一定,谁抢到CPU,谁执行。
Q4:如何区分父子进程?
A4:通过fork的返回值。

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
int main(int argc,const char* argv[])
{pid_t pid;for(int i=0;i<4;i++){printf("---------------i=%d\n",i);}pid = fork();if(pid >0){printf("parent process,pid=%d\n",getpid());}else if(pid ==0){printf("child  process,pid=%d\n",getpid());}for(int i=0;i<4;i++){printf("---------------i=%d\n",i);}return 0;
}

在这里插入图片描述
在这里插入图片描述
有上面实验的结果可知,子进程中是从fork下面的开始开始执行的。所以子进程虽然有代码段,但是不会执行。让父进程睡一会(父进程结束的太快了,已经结束了,使得子进程将init进程作为父进程了)
在这里插入图片描述
出现上面的原因:
在这里插入图片描述
2、ps和kill命令
在这里插入图片描述
Q:如何获取当前进程的id?
A:
#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<string.h>
int main(int argc, const char* argv[])
{
while(1)
{
printf(“hello,world\n”);
sleep(1);
}
return 0;
}
`在这里插入图片描述
在这里插入图片描述
TTY :就是终端,au显示依赖终端的选项。
Q:终端对于进程来说有什么用呢?
A:没有终端就看不到输出,所以依赖终端的进程是需要和用户交互的。
在这里插入图片描述
|:表示管道。
在这里插入图片描述
kill:发信号给某个进程
在这里插入图片描述
只需学1-31个信号即可。
杀死某个进程:kill -9 (仅为9号信号为SIGKILL表示杀死信号)
在这里插入图片描述
3、进程间数据共享
关于fork,刚fork之后,两个地址空间用户区数据完全相同,后续各自都做了各自不同的操作,各个进程的地址空间中的数据是完全独立的,如下图所示,n=24子、父一样的,在子父进程各自对n进行操作时,是互不影响的,一个++,一个–;扩展:研究这个n = 24,但对于这个n只是进行读操作时,那么在物理内存中n是一份,也就是子父进程只是读这个n,而不改变,这样可以节省内存,也就是读时共享n;但是在进行读写操作时,因为可以子父进程可以修改它,为了子父进程互不影响,子进程就拷贝一份,也就是不是共享的。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
上图所示,在父或子进程对变量进行写操作时,都会在物理内存开辟一块内存保存修改的值,而且父子变量内存不共享。
Q:父、子进程之间,是否可以通过一个全局变量进行通信?
A:不能,因为根据上面的原理,写复制,父子各自的变量物理内存不一样,所以内存不能共享。
小结:读时共享,写时复制
扩展:需要实现共享就牵涉到进程间的通信。
4、exec函数族
(1)作用
①让父子进程执行不相干的操作
②父子进程代码段一样的,而exec函数组可以替换父子空间的源代码,也就是.text段
在这里插入图片描述
注意:替代.text中代码的是可执行文件源代码,因为是进程,所以需要是可执行的程序。其中的ls是一个例子,它是shell中的一个可执行文件,所以当替换只有,进程就相当于执行命令ls了。鸠占鹊巢的感觉。
(2)使用
例子:
在这里插入图片描述
在这里插入图片描述
“who can arrive here”,只执行了一次,并且是在父进程3047中,而子进程3048执行的程序是ls,所以得出结论,当子进程使用execl()时,子进程中的.text中的源代码全部被execl程序中的代码所替换,也就不能执行if(pid==0)外的内容了。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5、进程回收
(1)孤儿进程
①爹生孩子
②爹先死,孩子还活着,孩子就叫做孤儿进程
③孤儿被init进程领养,init进程变为孤儿进程的父亲。(这就是为什么写程序会出现子进程的父进程变为1,也就是原来的父进程执行的太快了,以至于原来父进程结束了,而子进程还没执行完,就成孤儿了。)
④为了释放子进程占用的系统资源
进程结束之后,能够释放用户区空间;释放不了PCB,必须由父进程释放(key)。
在这里插入图片描述
这里就出现了孤儿进程被ppid=1的进程领养了。
(2)僵尸进程
①孩子死了,爹还活着,爹不去释放子进程的pcb,孩子就变成 了僵尸进程。(因为只能由父进程释放)
②不是活着的进程
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
z:表示zonbie僵尸的意思,defunct表示a.out进程为僵尸进程。
如何杀死僵尸进程呢?通过杀死他爹的进程就行了,也就是3516,直接杀死僵尸进程是不能消除的,相当于鞭尸。
在这里插入图片描述
在这里插入图片描述
(3)进程回收
①wait-阻塞函数(与socket差不多,也就是一直阻塞在哪,等待消息)
pid_t wait(int * status);
在这里插入图片描述
在这里插入图片描述
作用:因为子进程需要父进程进行回收,而且在并发运行的时候,父子进程的执行顺序是不一定的,所以需要wait函数去使得父进程等待子进程结束,然后回收,最后父进程结束,造成有顺序的执行。
在这里插入图片描述
在这里插入图片描述
如上died child pid是最后执行的,表明父进程是在子进程执行完,回收它之后执行完的。

在这里插入图片描述
在这里插入图片描述
这里最后的返回值为9,表明父进程一直执行到最后,所以返回了9,也就是 正常退出
当子进程一直循环不退出时,父进程将一直等待:
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

有两个进程在运行,kill -9 4051 。通过信号杀死子进程,预期不会返回12,会返回9
在这里插入图片描述
终止了。
小结:
父进程结束的比子进程早,则会造成子进程成为孤儿进程;
父进程结束的比子进程晚,并且父进程一直不退出,则会造成子进程成为僵尸进程;(所以消灭僵尸进程是通过kill父进程达到目的)
解决方法:通过父进程中调用wait函数。
在这里插入图片描述
在这里插入图片描述

这篇关于Linux系统编程:step1的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/196761

相关文章

Linux ls命令操作详解

《Linuxls命令操作详解》通过ls命令,我们可以查看指定目录下的文件和子目录,并结合不同的选项获取详细的文件信息,如权限、大小、修改时间等,:本文主要介绍Linuxls命令详解,需要的朋友可... 目录1. 命令简介2. 命令的基本语法和用法2.1 语法格式2.2 使用示例2.2.1 列出当前目录下的文

利用Python快速搭建Markdown笔记发布系统

《利用Python快速搭建Markdown笔记发布系统》这篇文章主要为大家详细介绍了使用Python生态的成熟工具,在30分钟内搭建一个支持Markdown渲染、分类标签、全文搜索的私有化知识发布系统... 目录引言:为什么要自建知识博客一、技术选型:极简主义开发栈二、系统架构设计三、核心代码实现(分步解析

Linux中的计划任务(crontab)使用方式

《Linux中的计划任务(crontab)使用方式》:本文主要介绍Linux中的计划任务(crontab)使用方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录一、前言1、linux的起源与发展2、什么是计划任务(crontab)二、crontab基础1、cro

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将

Python FastAPI+Celery+RabbitMQ实现分布式图片水印处理系统

《PythonFastAPI+Celery+RabbitMQ实现分布式图片水印处理系统》这篇文章主要为大家详细介绍了PythonFastAPI如何结合Celery以及RabbitMQ实现简单的分布式... 实现思路FastAPI 服务器Celery 任务队列RabbitMQ 作为消息代理定时任务处理完整

Linux系统配置NAT网络模式的详细步骤(附图文)

《Linux系统配置NAT网络模式的详细步骤(附图文)》本文详细指导如何在VMware环境下配置NAT网络模式,包括设置主机和虚拟机的IP地址、网关,以及针对Linux和Windows系统的具体步骤,... 目录一、配置NAT网络模式二、设置虚拟机交换机网关2.1 打开虚拟机2.2 管理员授权2.3 设置子

揭秘Python Socket网络编程的7种硬核用法

《揭秘PythonSocket网络编程的7种硬核用法》Socket不仅能做聊天室,还能干一大堆硬核操作,这篇文章就带大家看看Python网络编程的7种超实用玩法,感兴趣的小伙伴可以跟随小编一起... 目录1.端口扫描器:探测开放端口2.简易 HTTP 服务器:10 秒搭个网页3.局域网游戏:多人联机对战4.

Linux系统中卸载与安装JDK的详细教程

《Linux系统中卸载与安装JDK的详细教程》本文详细介绍了如何在Linux系统中通过Xshell和Xftp工具连接与传输文件,然后进行JDK的安装与卸载,安装步骤包括连接Linux、传输JDK安装包... 目录1、卸载1.1 linux删除自带的JDK1.2 Linux上卸载自己安装的JDK2、安装2.1

Java并发编程必备之Synchronized关键字深入解析

《Java并发编程必备之Synchronized关键字深入解析》本文我们深入探索了Java中的Synchronized关键字,包括其互斥性和可重入性的特性,文章详细介绍了Synchronized的三种... 目录一、前言二、Synchronized关键字2.1 Synchronized的特性1. 互斥2.

Linux卸载自带jdk并安装新jdk版本的图文教程

《Linux卸载自带jdk并安装新jdk版本的图文教程》在Linux系统中,有时需要卸载预装的OpenJDK并安装特定版本的JDK,例如JDK1.8,所以本文给大家详细介绍了Linux卸载自带jdk并... 目录Ⅰ、卸载自带jdkⅡ、安装新版jdkⅠ、卸载自带jdk1、输入命令查看旧jdkrpm -qa