Linux:进程(二)

目录

一、cwd的理解

二、fork的理解

1.代码共享

2.各司其职

3.fork的返回值

三、进程状态

1.进程排队

2.进程状态

运行状态


一、cwd的理解

        cwd(current working directory)。译为当前工作目录

        在C语言中,使用fopen函数打开文件时,第一个参数为当前目录下的某个文件的文件名,那么如何理解“当前目录”

        我们已经知道在/proc目录下,以文件的形式存放着每一个进程。

        需要注意的是,只有当一个可执行程序被执行后,对应的进程文件才会在/proc目录下出现。

[euto@VM-4-13-centos 24915]$ ./myprocess 
i am a process! id: 3800,fid: 2963 
i am a process! id: 3800,fid: 2963 
i am a process! id: 3800,fid: 2963 
i am a process! id: 3800,fid: 2963 
···········

        同时在/proc目录下,出现一个进程目录3800

[euto@VM-4-13-centos 24915]$ ls /proc
1      16     264    36    560   acpi         kallsyms      scsi
10     170    265    3647  562   buddyinfo    kcore         self
1005   17110  269    37    563   bus          keys          slabinfo
1071   18     27     3721  568   cgroups      key-users     softirqs
1074   1825   275    376   575   cmdline      kmsg          stat
1077   19     28     38    6     consoles     kpagecount    swaps
11     196    28150  3800  637   cpuinfo      kpageflags    sys
1100   2      285    4     638   crypto       loadavg       sysrq-trigger
1196   20     28704  400   639   devices      locks         sysvipc
12     21     28720  403   640   diskstats    mdstat        timer_list
1206   22     28721  407   641   dma          meminfo       timer_stats
1207   23     29     4452  65    driver       misc          tty
1218   23737  290    46    671   execdomains  modules       uptime
1219   24     291    48    7     fb           mounts        version
13     25     2959   49    8     filesystems  mtrr          vmallocinfo
1347   259    2962   50    9     fs           net           vmstat
1354   25995  2963   51    9648  interrupts   pagetypeinfo  xpmem
1373   26     30772  516   9684  iomem        partitions    zoneinfo
14     262    3123   5375  9802  ioports      sched_debug
14075  263    35     5421  9803  irq          schedstat

        我们可以查看进程3800的目录。

[euto@VM-4-13-centos 24915]$ ll /proc/3800 
total 0
dr-xr-xr-x 2 euto euto 0 Sep 18 10:20 attr
-rw-r--r-- 1 euto euto 0 Sep 18 10:20 autogroup
-r-------- 1 euto euto 0 Sep 18 10:20 auxv
-r--r--r-- 1 euto euto 0 Sep 18 10:20 cgroup
--w------- 1 euto euto 0 Sep 18 10:20 clear_refs
-r--r--r-- 1 euto euto 0 Sep 18 10:17 cmdline
-rw-r--r-- 1 euto euto 0 Sep 18 10:20 comm
-rw-r--r-- 1 euto euto 0 Sep 18 10:20 coredump_filter
-r--r--r-- 1 euto euto 0 Sep 18 10:20 cpuset
lrwxrwxrwx 1 euto euto 0 Sep 18 10:17 cwd -> /home/euto/linux/24915
-r-------- 1 euto euto 0 Sep 18 10:17 environ
lrwxrwxrwx 1 euto euto 0 Sep 18 10:17 exe -> /home/euto/linux/24915/myprocess
dr-x------ 2 euto euto 0 Sep 18 10:17 fd
dr-x------ 2 euto euto 0 Sep 18 10:20 fdinfo
-rw-r--r-- 1 euto euto 0 Sep 18 10:20 gid_map
-r-------- 1 euto euto 0 Sep 18 10:20 io
·······················

        需要注意两个信息,exe所指向的就是该进程对应的可执行程序所在目录

        这里还有一个信息就是cwd,不难总结出来,cwd和进程是深深绑定的,换句话说,我们平时说讲的“当前目录”,其实就是和进程绑定的cwd。因此,在C语言中使用fopen打开当前目录下某个文件的操作,其实就是可执行程序运行起来后,对应的进程中cwd所指目录下的某个文件。

        下面对这个结论作验证,通过执行指令chdir来演示,chdir的功能用来改变当前的工作目录。

CHDIR(2)                   Linux Programmer's Manual                  CHDIR(2)NAMEchdir, fchdir - change working directorySYNOPSIS#include <unistd.h>int chdir(const char *path);int fchdir(int fd);
······

        修改源文件为以下内容。

[euto@VM-4-13-centos 24915]$ cat myprocess.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{printf("当前进程pid:%d\n",getpid());printf("修改目录前\n");sleep(30);printf("修改目录后\n");chdir("/home/euto/");sleep(30);FILE* fp =  fopen("test.txt","w");fclose(fp);return 0;
}

        演示结果应该为:修改目录前,cwd为当前文件所在的目录24915。修改目录后,cwd更改为/home/euto,执行fopen打开文件test.txt时,由于test.txt文件并不存在,所以新建一个文件test.txt,新建文件所在的目录是/home/euto

[euto@VM-4-13-centos 24915]$ ./myprocess 
当前进程pid:16846
修改目录前
[euto@VM-4-13-centos 24915]$ ll /proc/16846
total 0
dr-xr-xr-x 2 euto euto 0 Sep 18 10:43 attr
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 autogroup
-r-------- 1 euto euto 0 Sep 18 10:43 auxv
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cgroup
--w------- 1 euto euto 0 Sep 18 10:43 clear_refs
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cmdline
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 comm
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 coredump_filter
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cpuset
lrwxrwxrwx 1 euto euto 0 Sep 18 10:43 cwd -> /home/euto/linux/24915
-r-------- 1 euto euto 0 Sep 18 10:43 environ
lrwxrwxrwx 1 euto euto 0 Sep 18 10:43 exe -> /home/euto/linux/24915/myprocess
dr-x------ 2 euto euto 0 Sep 18 10:43 fd
dr-x------ 2 euto euto 0 Sep 18 10:43 fdinfo
·······

        程序执行chdir修改目录后。

[euto@VM-4-13-centos 24915]$ ./myprocess 
当前进程pid:16846
修改目录前
修改目录后
[euto@VM-4-13-centos 24915]$ ll /proc/16846
total 0
dr-xr-xr-x 2 euto euto 0 Sep 18 10:43 attr
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 autogroup
-r-------- 1 euto euto 0 Sep 18 10:43 auxv
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cgroup
--w------- 1 euto euto 0 Sep 18 10:43 clear_refs
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cmdline
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 comm
-rw-r--r-- 1 euto euto 0 Sep 18 10:43 coredump_filter
-r--r--r-- 1 euto euto 0 Sep 18 10:43 cpuset
lrwxrwxrwx 1 euto euto 0 Sep 18 10:43 cwd -> /home/euto
-r-------- 1 euto euto 0 Sep 18 10:43 environ
lrwxrwxrwx 1 euto euto 0 Sep 18 10:43 exe -> /home/euto/linux/24915/myprocess
dr-x------ 2 euto euto 0 Sep 18 10:43 fd
········

        查看/home/euto目录,发现test.txt文件新建在了这个目录,和预期符合。

[euto@VM-4-13-centos 24915]$ ls /home/euto/
linux  test.txt

二、fork的理解

        运行man fork查看fork的相关介绍。

FORK(2)                                                             Linux Programmer's Manual                                                             FORK(2)NAMEfork - create a child processSYNOPSIS#include <unistd.h>pid_t fork(void);

        fork这个函数用来创建一个子进程。

        父进程和子进程的关系:一个父进程可以有多个子进程,而一个子进程的父进程是唯一的。


        fork的返回值介绍。

RETURN VALUEOn success, the PID of the child process is returned in the parent, 
and 0 is returned in the child.  On failure, -1 is returned in the  parent, 
no  child process is created, and errno is set appropriately.

        子进程创建失败,返回负数。

        子进程创建成功,给父进程返回子进程的pid,给子进程返回0。(pid都是大于0的整数) 


1.代码共享

  • 结论:使用fork创建子进程后,父进程和子进程共享代码。

        解释:

        在目录24918下编辑源文件myprocess.c的内容。

[euto@VM-4-13-centos 24918]$ cat myprocess.c
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{printf("fork之前:i am a process ,pid:%d,ppid:%d",getpid(),getppid());fork();printf("fork之后:i am a process ,pid:%d,ppid:%d",getpid(),getppid());return 0;
}

        运行结果显示。

[euto@VM-4-13-centos 24918]$ ./myprocess 
fork之前:i am a process ,pid:16709,ppid:6682
fork之后:i am a process ,pid:16709,ppid:6682//父进程
fork之后:i am a process ,pid:16710,ppid:16709//子进程

        第二句printf被打印了两次的原因是,父进程和子进程分别进行了打印。在执行fork这个函数后,子进程就已经在内存中存在了,子进程和父进程指向同一个可执行程序,在fork函数后需要执行的代码被父子进程共享

        其中,一条打印结果的ppid是另一条打印结果的pid,说明这是父子进程。

        关于子进程的PCB,大部分内容和父进程相同。

        关于共享的可执行程序,代码和数据都只有一份。


2.各司其职

  • 结论:一般而言,父进程和子进程完成的功能是不同的,源文件的代码只有一份,但是通过条件判断语句让父进程和子进程可以实现不同的功能

        解释:编辑源文件myprocess.c的内容如下。

int main()
{printf("fork之前i am a process,pid:%d ,ppid:%d\n",getpid(),getppid());sleep(5);printf("开始创建子进程\n");pid_t id = fork();if(id < 0){return 1;}else if(id == 0){//子进程while(1){printf("fork之后,我是子进程,pid:%d,ppid:%d,id:%d\n",getpid(),getppid(),id);sleep(1);}}else{//父进程while(1){printf("fork之后,我是父进程,pid:%d,ppid:%d,id:%d\n",getpid(),getppid(),id);sleep(1);}}return 0;
}

        运行结果如下。

[euto@VM-4-13-centos 24918]$ ./myprocess 
fork之前i am a process,pid:32557 ,ppid:30035
开始创建子进程
fork之后,我是父进程,pid:32557,ppid:30035,id:32570
fork之后,我是子进程,pid:32570,ppid:32557,id:0
fork之后,我是父进程,pid:32557,ppid:30035,id:32570
fork之后,我是子进程,pid:32570,ppid:32557,id:0
fork之后,我是父进程,pid:32557,ppid:30035,id:32570
fork之后,我是子进程,pid:32570,ppid:32557,id:0
fork之后,我是父进程,pid:32557,ppid:30035,id:32570
fork之后,我是子进程,pid:32570,ppid:32557,id:0
······

        程序运行成功后,父进程和子进程执行各自的代码,但是源文件的代码在内存中只有一份,数据也是只有一份。

        如果子进程在执行的过程中修改某一个变量,实际上并不是修改变量本来的内存空间,而是在修改之前,完成一个“写时拷贝”的操作,拷贝一份新的空间用来给子进程操作,父进程也是如此。


3.fork的返回值

  • 为什么fork返回时,给父进程返回子进程的pid,给子进程返回0?

        如果作为子进程,只需要调用getppid即可获取到父进程,因为父进程是唯一的;如果作为父进程,是没有办法直接获取到子进程的pid的,因为子进程不唯一,可以有多个。

  • fork给两个进程返回了不同的值,众所周知,函数不可能返回两个值,因此,可以判断,fork函数返回了两次,那么fork是如何返回两次的?

        我们假设这是fork函数的函数体。

        在return语句之前,fork处理创建子进程相关的操作,且执行return这一行代码之前,子进程就已经被创建出来并活跃在内存中return语句的本质就写入到不同的进程,可以看作是特殊的返回,执行两次return分别返回到不同的进程中

  • 源代码中的id是一个变量,为什么一个变量可以有两个值?

        操作系统在设计进程的时候,就保证了进程之间是彼此独立的,互相不影响。且利用了虚拟内存等其他技术,使得在Linux下,用一个变量表示了不同的内存空间


        编写一次创建多个进程的源程序,代码如下。

const int num = 10;
void worker()
{int cnt = 10;while(cnt){printf("child %d is running,cnt:%d\n",getpid(),cnt);--cnt;sleep(1);}
}
int main()
{for(int i =0;i < num; ++i){pid_t id = fork();if(id<0){break;}if(id == 0){worker();exit(0);}printf("父进程成功创建子进程,id:%d\n",id);sleep(1);}sleep(10);return 0;
}

三、进程状态

1.进程排队

  • 为什么存在进程排队这样的现象?

        进程出现了排队,一定是在等待某个资源,毕竟硬件资源有限

  • 进程不是一直在运行的。进程在CPU上,也不是一直在运行的。

        比如,当程序执行到scanf这一行的时候,程序在等待键盘的输入,即在等待硬件资源(也可能是软件资源),因此进程不是一直在运行的。

        在CPU上,由于时间片的设计,CPU也不是一直在运行同一个进程。

  • 进程=PCB + 可执行程序,所谓的进程排队是可执行程序在排队还是PCB在排队?

        排队一定是利用了队列这种数据结构,那么单位类型是可执行程序的话消耗将会巨大无比,因此涉及排队,都是利用队列对PCB作排队

  • 不难发现,一个task_struct,既要利用链表这种数据结构,又要利用队列这种数据结构,那么底层是怎么实现的呢,是存储两份数据吗?

        并不是下面这样的实现。

        而是在task_struct内部封装链表结点或者队列结点,因此一个task_struct可以被链入到多个数据结构中。

         那么,在已知listnode地址的情况下,如何操作task_struct其他数据呢,这就和偏移量有关。

2.进程状态

        进程的三种状态:运行,阻塞,挂起

  • 状态是什么

        本质上,就是task_struct中的一个整型变量。

struct task_struct
{int status;····
}

        用整型变量表示不同的状态就类似define定义

#define new 1
#define ready 2
#define running 3
#define block 4
·····
  • 设计状态这一个属性的意义。

        通过进程的状态来决定下一步进程要做的动作


运行状态

        一个CPU对应一个运行队列当进程在运行队列中排队时,即为运行状态

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143144.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

React-Hook原理

前置知识 闭包 在 Hook 的应用比如 dispatch 函数,也就是 useState 返回的第二个参数 闭包是指有权访问另一个函数作用域中变量或方法的函数,创建闭包的方式就是在一个函数内创建闭包函数,通过闭包函数访问这个函数的局部变量, 利用闭包可以突破作用链域的特性,将函数内部…

IDEA去除掉虚线,波浪线,和下划线实线的方法

初次安装使用IDEA&#xff0c;总是能看到导入代码后&#xff0c;出现很多的波浪线&#xff0c;下划线和虚线&#xff0c;这是IDEA给我们的一些提示和警告&#xff0c;但是有时候我们并不需要&#xff0c;反而会让人看着很不爽&#xff0c;这里简单记录一下自己的调整方法&#…

基于ssm+vue+uniapp的面向企事业单位的项目申报小程序

开发语言&#xff1a;Java框架&#xff1a;ssmuniappJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;M…

水果成熟度检测系统源码分享

水果成熟度检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

mysql事务的隔离级别学习

事务的隔离级别: ⅰ. 读未提交 ⅱ. 对已提交 &#xff08;解决 脏读&#xff09; ⅲ. 可重复读 &#xff08;解决 不可重复读&#xff09; ⅳ. 串行化 &#xff08;解决 脏读 不可重复读 幻读 问题 &#xff09; 隔离级别分类如下&#xff0c;在不同的隔离级别下可能产生不…

LabVIEW提高开发效率技巧----使用LabVIEW工具

LabVIEW为开发者提供了多种工具和功能&#xff0c;不仅提高工作效率&#xff0c;还能确保项目的质量和可维护性。以下详细介绍几种关键工具&#xff0c;并结合实际案例说明它们的应用。 1. VI Analyzer&#xff1a;自动检查代码质量 VI Analyzer 是LabVIEW提供的一款强大的工…

Python 之数据库操作(Python Database Operations)

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:Linux运维老纪的首页…

新书出版,大陆首本NestJS图书《NestJS全栈开发解析:快速上手与实践》

新书全栈实战项目&#xff1a;数字门店管理平台开源啦&#x1f389;&#x1f389;&#x1f389; GitHub地址&#xff08;持续更新NestJS企业级实践&#xff09;&#xff1a;欢迎star⭐️⭐️⭐️ 前端ReactTypeScriptVite 后端NestMySQLRedisDocker 前言 对&#xff0c;你没看…

esp32s3分区表配置及读写

一、分区表介绍 每片 ESP32-S3 的 flash 可以包含多个应用程序&#xff0c;以及多种不同类型的数据&#xff08;例如校准数据、文件系统数据、参数存储数据等&#xff09;。因此&#xff0c;在 flash 的 默认偏移地址 0x8000 处烧写一张分区表。 分区表中的每个条目都包括以下…

Lnux驱动开发学习 -- imx6ull LCD驱动学习

文章目录 环境LCD设备树信息imx6ull的LCD驱动 环境 正点提供的 linux 4.15 LCD设备树信息 看下imx6ull提供的设备树信息&#xff1a; arch/arm/boot/dts/imx6ull.dtsi&#xff1a;lcdif: lcdif021c8000 {compatible "fsl,imx6ul-lcdif", "fsl,imx28-lcdif&…

JDBC编程详细总结

一、JDBC编程 JDBC编程有标准步骤(八股文) 注册驱动 将sql语句的运行环境加载到JVM 连接数据库 获得执行SQL的对象 执行SQL语句,获得结果 关流 1、 注册驱动 Class.forName("com.mysql.jdbc.Driver");//5.7版本 加载驱动 Class.forName("com.mysql.cj.jdb…

Android TV RecyclerView列表获得焦点左右换行

在TV上&#xff0c;用RecyclerView显示一个列表&#xff0c;飞鼠遥控左右遥控获得Item焦点&#xff0c;到最后一个进行右键换行&#xff0c;是不能做到的&#xff0c;因此需要监听key事件处理换行。 效果图如下 代码实现 Item.xml布局 <?xml version"1.0" enc…

红帽 Quay- 配置镜像代理缓存

《OpenShift / RHEL / DevSecOps 汇总目录》 说明&#xff1a;本文已经在 Quay 3.12 环境中验证 说明&#xff1a;可先根据《红帽 Quay - 安装篇》完成 Quay 安装。 镜像代理缓存功能 Quay 的镜像代理缓存功能可以将用户拉取的远程镜像保存到本地 Quay 的 proxy cache 中&am…

C++速通LeetCode中等第2题-最长连续序列

方法一&#xff0c;排序后遍历&#xff0c;后减前1&#xff0c;计数&#xff0c; 相等跳过&#xff0c;后减前&#xff01;1就保存。 class Solution { public:int longestConsecutive(vector<int>& nums) {vector<int> ans;int count 1;sort(nums.begin(),n…

Facebook的用户隐私保护:从争议到革新

Facebook早期的数据收集方式引发了隐私担忧。平台的快速增长和用户数据的大规模收集使得隐私问题逐渐显现。尤其是在2018年&#xff0c;剑桥分析事件暴露了数千万用户数据被不当使用的问题。这一事件揭示了Facebook在数据保护方面的严重漏洞&#xff0c;引发了公众对隐私保护的…

C++中的const \static \this

目录 前言 一、const关键字 1、const修饰类的成员变量 2、const修饰类的成员函数 3、const修饰类的对象 二、static关键字 1、static修饰类中的成员变量 1. 共享性 2. 初始化 3. 访问权限 4. 内存分配 5. 不依赖于对象 2、static修饰类中的成员函数 三、this关键字…

「C++系列」异常处理

【人工智能教程】&#xff0c;前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。 点击跳转到网站&#xff1a;【人工智能教程】 文章目录 一、异常处理1. 基本概念2. 示例代码3. 注意事项 二、常见的异常类…

三维天地创新方案助力实验室信息自动化技术深入发展

实验室环境条件控制非常重要,它直接影响着最终的实验或检测结果。例如不同的实验室对于温湿度有不同的要求,这就给实验室温湿度监测与采集带来了一定的困难。 三维天地自主研发的实验室信息管理系统(SW-LIMS)提出了一种检化验记录温湿度自动采集的创新方案,这一方案致力于实现…

一键文本提示实现图像对象高质量剪切与透明背景生成

按照提示词裁剪 按照边框裁剪 要实现您描述的功能,即通过一个文本提示就能自动从图片中切割出指定的对象并生成一个带有透明背景的新图像,这需要一个结合了先进的计算机视觉技术和自然语言处理能力的系统。这样的系统可以理解输入的文本指令,并将其转化为对图像内容的精确分…

解决nginx代理SSE接口的响应没有流式返回

目录 现象原来的nginx配置解决 现象 前后端分离的项目&#xff0c;前端访问被nginx反向代理的后端SSE接口&#xff0c;预期是流式返回&#xff0c;但经常是很久不响应&#xff0c;一响应全部结果一下子都返回了。查看后端项目的日志&#xff0c;响应其实是流式产生的。推测是n…