Linux基础和系统编程 下

简介: Linux基础和系统编程 下

Linux基础和系统编程 下


进程和程序以及CPU有关

1.进程是运行起来的程序,进程要占用系统资源

进程要占用内存,执行计算指令要占用CPU,总线

2.程序是死的,程序占磁盘空间

3.一个可执行文件可以在多个终端中运行

4.程序能看到,进程看不到

5.并发:在操作系统中,一个时间段中有多个进程都处于已启动到运行完毕的状态

6.单道程序设计:所有进程一个一个排队,若A阻塞,B只能等待,即使CPU处于空闲状态。在人机交互时阻塞的出现是必然的。所有这种模型在系统资源利用上都及其不合理,存在不就就淘汰了。

比如微软的道斯系统

7.多道程序设计:在计算机内存中存放几道相互独立的程序,它们在管理程序的控制下,相互穿插的运行,多道程序设计需要硬件作为保证。

8.单核CPU也能并发,A进程完成一点,未全部完成,B开始运行,B没有完成,C开始运行

通过时钟中断来执行

9.存储介质

寄存器

cache(缓存)

内存(电信号)

硬盘(物理方法读取)

网络(几乎可以认为存储是无线的)

从上到下存储量越来越大,速度越来越慢

一个寄存器是4096字节,4kb

10.CPU和MMU

CPU由ALU算数逻辑单元(只会算加减),寄存器堆,译码器,预取器组成

MMU是虚拟内存映射单元,在CPU内部

虚拟内存和物理内存映射关系

1.程序不占用内存,进程占用内存

2.kernel有pcb进程控制块,有一些成员变量,进程描述符

3.

虚拟地址(真正的物理地址在内存条上)./a.out

image.png

./b.out

image.png

想把虚拟地址放在内存条上就需要MMU

如果两个进程虚拟内存地址一样,分块映射

4.一个page是4kb,MMU是4kb,一个寄存器是4kb

5.当申请的内存过大,需要连续空间时,MMU需要映射多个内存条区域

6.操作系统只有一个,所有进程的kernel共享,所以所有进程位于kernel的pcb都映射到内存条的一块区域内

7.MMU可以修改访问级别,CPU会将内存分级(Windows分4级,Linux分2级),MMU可以进行权级切换

pcb进程控制块

1.一个寄存器只有4Byte(32bit)

2.进程控制块:每个进程在内核中都有一个进程控制块来维护进程相关信息,Linux内核的进程控制块是task struct结构体

/user/src/linux-headers-3.16.0-30/include/linux/sched.h文件可以查看struct task_struct结构体的定义

3.需要掌握

进程id:每个进程有唯一的id

进程的状态:初始,就绪(等待CPU分配时间片),运行,挂起(等待除CPU以外的其他资源主动放弃CPU),停止

进程切换时需要保存和恢复的一些CPU寄存器(CPU正在计算,时间片结束了,需要将这个进程的寄存器数据存起来,再次运行这个进程时将值放回寄存器)

描述虚拟地址空间的信息

描述控制终端的信息

当前工作目录位置

umask掩码(不同进程有不同的umask掩码)

文件描述符表,包含很多指向file结构体的指针

和信号相关的信息

用户id和主id

会话Session和进程组

进程可以使用的资源上限

ps aux查询进程,第二列PID就是进程

环境变量

LD_LIBRARY_PATH动态连接器

PATH记录可执行文件目录位置

echo $PATH可以将这个环境变量打印

SHELL解析命令

TERM当前终端类型

LANG语言和locale,决定字符编码以及时间,货币等信息的显示格式

HOME当前用户的宿主目录

Fork函数原理

1.创建一个子进程

返回值为整数没有参数

2.父进程有的子进程都有,子进程执行fork();下面的

成功子进程会给父进程返回一个0,父进程返回子进程的id

Fork创建子进程

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main()
{
•   printf("before fork--1-------\n");
•   printf("before fork--2-------\n");
•   printf("before fork--3-------\n");
•   printf("before fork--4-------\n");
•   printf("before fork--5-------\n");
•   pid_t pid=fork();
•   if(pid==-1)
•   {
•       perror("fork error");
•       exit(1);
•   }
•   else if(pid==0)
•   {
•       printf("-------child is created\n");
•   }
•   else if(pid>0)
•   {
•       printf("-------parent process:my chid is%d\n",pid);
•   }
•   printf("===========end of file\n");
•   return 0;
}

before fork 1,2,3,4执行一次

===========end of file执行两次,因为fork之后的子进程和父进程都会执行

getpid和getppid

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main()
{
    printf("before fork--1-------\n");
    printf("before fork--2-------\n");
    printf("before fork--3-------\n");
    printf("before fork--4-------\n");
    printf("before fork--5-------\n");
    pid_t pid=fork();
    if(pid==-1)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid==0)
    {
        printf("-------child is created,pid=%d\n,parent_pid=%d",getpid(),getppid());
    }
    else if(pid>0)
    {
        printf("-------parent process:my chid is%d,mypid=%d,myparent_pid=%d\n",pid,getpid(),getppid());
    }
    printf("===========end of file\n");
    return 0;
}

ps aux | grep 7876

父进程的父进程是bash

循环创建N个子进程

1.一个fork函数调用可以创建一个子进程,那么创建N个子进程应该如何实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main()
{
    int i;
    for(i=0;i<5;i++){
    pid_t pid=fork();       //每次所有父进程,子进程,子进程产生的子进程都会产生一个子进程
    if(pid==-1)
    {
        perror("fork error");
        exit(1);
    }
    else if(pid==0)
    {
        printf("-------child is created,pid=%d\n,parent_pid=%d",getpid(),getppid());
    }
    else if(pid>0)
    {
        printf("-------parent process:my chid is%d,mypid=%d,myparent_pid=%d\n",pid,getpid(),getppid());
    }
    }
    return 0;
}

2.

#include<stdio.h>
​#include<stdlib.h>
​#include<string.h>
​#include<unistd.h>
​#include<pthread.h>
int main()
{
    int i;
    for(i=0;i<5;i++){
    if(fork()==0)
    break;
    }
    if(i==5)
       printf("I'm parent");
    else
    printf("I'm %dth child",i+1);
    return 0;
}

每个进程会争取cpu,导致顺序不一致

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int main()
{
    int i;
    for(i=0;i<5;i++){
    if(fork()==0)
    break;
    }
    if(i==5)
    {
        sleep(5);
       printf("I'm parent");
       }
    else{
    sleep(i);
    printf("I'm %dth child",i+1);
    }
    return 0;
}

父子进程共享哪些内容

1.父子进程之间在fork之后

相同处:全局变量,data,text,栈,堆,环境变量,用户ID,宿主目录,进程工作目录,信号处理方式

不同处:进程Id,fork返回值,父进程id,进程运行时间,闹钟(定时器),未决信号集

似乎,子进程复制了父进程0~3G用户内容,以及父进程的PCB,但是pid不同,实际不是,父子进程间遵循读时共享写时复制的原则。这样设计,无论子进程执行父进程的逻辑还是执行自己的逻辑都能节省内存开销

2.躲避父子进程共享全局变量的知识误区

3.共享:1.文件描述符(打开文件的结构体) 2.mmap建立的映射区

父子进程gdb调试

1.使用gdb调试的时候,gdb只能跟踪一个进程。可以在fork函数调用之前,通过指令设置gdb调试工具跟踪父进程或者是跟踪子进程。默 认跟踪父进程

2.set follow-fork-mode child命令设置gdb在fork之后跟踪子进程

3.set follow-fork-mode parent跟踪父进程,默认父进程

exec函数族原理

1.fork创建子进程后执行的是和父进程相同的程序(但是可能执行不同的代码分支),子进程往往要调用一种exec函数以执行另一个程序。当进程调用一种exec函数时,该进程的用户空间代码和数据完全被新程序替换,从新程序的启动例程开始执行。调用exec并不创建新进程,所以调用exec前后该进程的id并未改变。

2.进程还是父进程的子进程,但是执行的内容不一样了,exec调用的部分不会返回给父进程,进程id不变

-execlp和execl函数

execlp函数

加载一个进程,借助PATH环境变量

该函数通常调用系统程序。如:ls,date,cp,cat等命令

int execlp(const char *file,const char *arg,...);

execlp("ls","-l","-d)

失败返回-1

int execl(const *path,const char *arg,...);

指定路径

execl("/bin/ls","ls","-l","-F",NULL);

exec函数族的特性

1.execvp函数

加载一个进程

int execvp(const char *file,char *const argv[]);

char *argv[]={"ls","-l","-h",NULL};

execvp("ls",argv);

2.exec函数一旦调用成功即执行新的程序,不返回,只有失败才会返回,错误值-1。所以通常直接在exec函数调用后直接调用perror()和exit(),无需if判断

孤儿进程和僵尸进程

孤儿进程

父进程先于进程结束,则子进程称为孤儿进程。子进程的父进程成为init进程,称为init进程领养孤儿进程。

orphan.c

ps aux

僵尸进程

进程终止,父进程尚未回收,子进程残留资源(PCB)存放在内核,变成僵尸进程。

PCB标记子进程死亡原因

[zoom]<defunct>

wait回收子进程

1.一个进程在终止时会关闭所有文件描述符,释放在用户空间分配的内存,但是它的PCB还保留着,内核在其中保存了一些信息,如果是正常终止则保存退出状态,如果是异常终止则保存着导致该进程终止的信号是哪个。这个进程的父进程可以调用wait或waitpid获取这些信息,然后彻底清除掉这个进程。一个进程的退出状态可以在shell中用特殊变量$查看因为shell是他的父进程,当它终止时Shell调用wait或waitpid得到它退出的状态同时彻底清除这个进程

2.父进程调用wait函数可以回收子进程的终止信息,该函数有三个功能: 1.阻塞等待子进程退出

2.回收子进程残留资源

3.获取子进程结束状态(退出原因)

3.pid_t wait(int *status);

pid_t waitpid(pid_t pid,int *status,int *options);

成功返回子进程的进程id,失败-1

获取子进程退出值和异常终止信号

1.使用宏函数

1.if(WIFEXITED(status))

为真说明子进程正常终止

WEXITSTATUS(status);

子进程返回值

2.WIFSIGNAL(status)

为真,异常终止

WTERMSIG(status)

取得使进程终止的那个信号的编号

2.所有进程终止都是信号

Linux基础命令学习资源

【麻省理工学院】MIT 计算机操作环境导论 Missing Semester (超强的计算机工具课)-_哔哩哔哩_bilibili

黑马程序员新版Linux零基础快速入门到精通,全涵盖linux系统知识、常用软件环境部署、Shell脚本、云平台实践、大数据集群项目实战等_哔哩哔哩_bilibili

相关实践学习
阿里云图数据库GDB入门与应用
图数据库(Graph Database,简称GDB)是一种支持Property Graph图模型、用于处理高度连接数据查询与存储的实时、可靠的在线数据库服务。它支持Apache TinkerPop Gremlin查询语言,可以帮您快速构建基于高度连接的数据集的应用程序。GDB非常适合社交网络、欺诈检测、推荐引擎、实时图谱、网络/IT运营这类高度互连数据集的场景。 GDB由阿里云自主研发,具备如下优势: 标准图查询语言:支持属性图,高度兼容Gremlin图查询语言。 高度优化的自研引擎:高度优化的自研图计算层和存储层,云盘多副本保障数据超高可靠,支持ACID事务。 服务高可用:支持高可用实例,节点故障迅速转移,保障业务连续性。 易运维:提供备份恢复、自动升级、监控告警、故障切换等丰富的运维功能,大幅降低运维成本。 产品主页:https://www.aliyun.com/product/gdb
相关文章
|
13天前
|
Linux
在 Linux 系统中,“cd”命令用于切换当前工作目录
在 Linux 系统中,“cd”命令用于切换当前工作目录。本文详细介绍了“cd”命令的基本用法和常见技巧,包括使用“.”、“..”、“~”、绝对路径和相对路径,以及快速切换到上一次工作目录等。此外,还探讨了高级技巧,如使用通配符、结合其他命令、在脚本中使用,以及实际应用案例,帮助读者提高工作效率。
52 3
|
13天前
|
监控 安全 Linux
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景
在 Linux 系统中,网络管理是重要任务。本文介绍了常用的网络命令及其适用场景,包括 ping(测试连通性)、traceroute(跟踪路由路径)、netstat(显示网络连接信息)、nmap(网络扫描)、ifconfig 和 ip(网络接口配置)。掌握这些命令有助于高效诊断和解决网络问题,保障网络稳定运行。
39 2
|
23天前
|
Linux 应用服务中间件 Shell
linux系统服务二!
本文详细介绍了Linux系统的启动流程,包括CentOS 7的具体启动步骤,从BIOS自检到加载内核、启动systemd程序等。同时,文章还对比了CentOS 6和CentOS 7的启动流程,分析了启动过程中的耗时情况。接着,文章讲解了Linux的运行级别及其管理命令,systemd的基本概念、优势及常用命令,并提供了自定义systemd启动文件的示例。最后,文章介绍了单用户模式和救援模式的使用方法,包括如何找回忘记的密码和修复启动故障。
42 5
linux系统服务二!
|
23天前
|
Linux 应用服务中间件 Shell
linux系统服务!!!
本文详细介绍了Linux系统(以CentOS7为例)的启动流程,包括BIOS自检、读取MBR信息、加载Grub菜单、加载内核及驱动程序、启动systemd程序加载必要文件等五个主要步骤。同时,文章还对比了CentOS6和CentOS7的启动流程图,并分析了启动流程的耗时。此外,文中还讲解了Linux的运行级别、systemd的基本概念及其优势,以及如何使用systemd管理服务。最后,文章提供了单用户模式和救援模式的实战案例,帮助读者理解如何在系统启动出现问题时进行修复。
42 3
linux系统服务!!!
|
7天前
|
Ubuntu Linux 网络安全
linux系统ubuntu中在命令行中打开图形界面的文件夹
在Ubuntu系统中,通过命令行打开图形界面的文件夹是一个高效且实用的操作。无论是使用Nautilus、Dolphin还是Thunar,都可以根据具体桌面环境选择合适的文件管理器。通过上述命令和方法,可以简化日常工作,提高效率。同时,解决权限问题和图形界面问题也能确保操作的顺利进行。掌握这些技巧,可以使Linux操作更加便捷和灵活。
14 3
|
2月前
|
Web App开发 搜索推荐 Unix
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
【10月更文挑战第21天】Linux系统之MobaXterm远程连接centos的GNOME桌面环境
252 4
Linux系统之MobaXterm远程连接centos的GNOME桌面环境
|
2月前
|
运维 监控 Linux
Linux系统之部署Linux管理面板1Panel
【10月更文挑战第20天】Linux系统之部署Linux管理面板1Panel
92 3
Linux系统之部署Linux管理面板1Panel
|
13天前
|
安全 网络协议 Linux
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。
本文详细介绍了 Linux 系统中 ping 命令的使用方法和技巧,涵盖基本用法、高级用法、实际应用案例及注意事项。通过掌握 ping 命令,读者可以轻松测试网络连通性、诊断网络问题并提升网络管理能力。
48 3
|
16天前
|
安全 Linux 数据安全/隐私保护
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。
在 Linux 系统中,查找文件所有者是系统管理和安全审计的重要技能。本文介绍了使用 `ls -l` 和 `stat` 命令查找文件所有者的基本方法,以及通过文件路径、通配符和结合其他命令的高级技巧。还提供了实际案例分析和注意事项,帮助读者更好地掌握这一操作。
35 6
|
16天前
|
Linux
在 Linux 系统中,`find` 命令是一个强大的文件查找工具
在 Linux 系统中,`find` 命令是一个强大的文件查找工具。本文详细介绍了 `find` 命令的基本语法、常用选项和具体应用示例,帮助用户快速掌握如何根据文件名、类型、大小、修改时间等条件查找文件,并展示了如何结合逻辑运算符、正则表达式和排除特定目录等高级用法。
50 6
下一篇
无影云桌面