当前位置: 首页> 教育> 培训 > 免费软件英文_建筑设计招标网站_友情链接什么意思_网站推广app下载

免费软件英文_建筑设计招标网站_友情链接什么意思_网站推广app下载

时间:2025/7/9 13:12:28来源:https://blog.csdn.net/in_seattle/article/details/143503302 浏览次数:0次
免费软件英文_建筑设计招标网站_友情链接什么意思_网站推广app下载

🌈个人主页:羽晨同学 

💫个人格言:“成为自己未来的主人~”  

我们上一篇文章当中讲到了进程的概念,我们知道进程信息是放到一个tast_struct的结构体当中的,这个结构体也叫做PCB。

PCB是内存级的操作,我们把这个结构体放到CPU当中。

首先,我们来说一下应该如何查看进程呢?

比如说,我们创建一个code的进程。

#include<stdio.h>
int main()
{while(1){printf("hello world\n");}return 0;
}
~                                                                        
~              

然后我们将这个代码运行起来,就创建了一个进程,接下来,让我们来查看我们的进程。

ps ajx | head -1 && ps ajx | grep code

通过这个命令,我们就可以查看到下面的进程列表。 

 其实这个命令本身就是好几个进程。

ps是一个,head是一个,grep本身就是一个,然后查看到的code也是一个,当我们想要取消掉grep进程的时候,可以后面加一个grep -v grep,就可以过滤掉grep进程

这个时候,就没有grep进程了。

其实把程序运行起来,本身就是在系统上启动一个进程。

像linux当中的指令,如:ls who am i pwd等都是系统对应的指令,都是系统对应的文件,相对应的,这种也都是启动的进程不过这种进程是瞬时的,一跑就跑完了。

还有一种不是瞬时的,就比如各种应用程序。

所以,进程分为两种:

执行完就推出的。

除非用户主动关闭,否则一直不退的(常驻进程:杀毒软件)

为了识别进程,所以进程是有编号的,也就是进程的pid。

同一个程序,在不同的时间启动,pid是会发生变化的,背后的原理是用了一个累加的计数器。

如果连续创建,pid是会连续的。

如果是我们刚才创建的进程,这个时候,他的PID是17293,当我们重新启动这个进程。

这个时候他的PID是19421

 此外,进程是具有唯一性的,体现到PID上就是,每个进程的PID都是不同的。

但是进程又是可以知道自己的PID的

pid_t  pid getpid();

通过这条指令,我们就可以获得进程的id值

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{pid_t id = getpid();while(1){printf("hello bit,i am a process pid: %d\n",id);sleep(1);}return 0;
}
~      

你看,这样子的话,我们就可以获得进程的PID值了 

我们取消进程的方式一般有两种,一种是ctrl c 还有一种是使用kill命令,其实两个方式的本质相同,都是杀进程。

比如说,这个时候我们启动一个进程,我们可以使用下面的这个命令来删除进程:

kill -9 21858

这个时候,这个进程就被删除了

在Linux中,在根目录下面有一个/proc(目录),全称叫做process,把进程的很多信息以文件的形式呈现出来。

这里面的一个个数字都是代表着进程的PID,每一个目录都是代表的一个进程。 

而每一个目录里面都存放着这个进程的所有属性。

只要启动了一个进程,就会瞬间在/proc里面创建一个这个PID的文件夹。

比如说,我刚才创建一个22877的进程,就可以在里面直接打开这个进程。

再次把这个进程干掉之后,就找不到这个文件夹了,也就没有22877这个东西了。

当我们进入这个目录的时候,有两个东西是值得我们关注的。

一个是exe,一个是cwd,

首先,我们说一下exe。

当我们这个时候终止这个进程,那就是删除了这个可执行文件。

但是这个时候代码还在运行,这是因为这个时候已经加载到内存当中了,删除的是磁盘当中的可执行文件。

 而对于那个cwd来说,cwd指的是current work dir,是当前的工作目录。

我们创建程序或者文件的时候,一般都是默认在当前目录下面创建的。,而这个当前目录,就是cwd所指向的路径。

比如说,这个时候我们新建一个程序:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{FILE *fp=fopen("log.txt","w");if(fp==NULL){}pid_t id = getpid();while(1){printf("hello bit,i am a process pid: %d\n",id);sleep(1);}return 0;
}

当这个代码运行之后,我们发现在当前目录下面创建一个log.txt的文件夹

怎么说呢,其实就是自己写的代码,当开始跑的时候,从上到下开始执行的时候,就是将cwd表示的路径拼接到log.txt的前面。所以会在当前路径下面新建文件。

如果想要改变工作路径的话,我们可以使用 int chdir,参数就是一个新的路径

比如说

chdir("/");

这个时候我们将默认的工作路径改到了根目录下面。

这个时候我们启动进程,看一下当前的cwd的指向。

看,这个时候的cwd就指向了根目录。

但是我们打开根目录却看到下面什么都没有,这是因为创建失败了(系统没有这个权限)

换到其他路径下面就可以了。 

对于我们前面的ps来说,ps的作用就是打来ls /proc 并且进行文本分析

/proc 目录不是磁盘级的文件,所以当系统重启的时候,这个目录下面也会刷新,进程相关的属性以文件的形式展现出来,不同担心影响系统的效率。

接下来,我们说一下ppid。

在linux系统重新启动之后,创建任何进程的时候,新创建的进程都是由父进程创建的。

我们通过下面这个指令来获取父进程:

int getppid();

比如说,我们创建下面的这个代码并形成进程。

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{/*chdir("/");FILE *fp=fopen("log.txt","w");if(fp==NULL){}*/pid_t ppid =getppid();pid_t id = getpid();while(1){printf("hello bit,i am a process pid: %d,ppid: %d\n",id,ppid);sleep(1);}return 0;
}

我们可以很明显的发现的是每一次pid都会发生变化,但是ppid却一直不发生变化。

在命令行当中,执行命令,执行程序,本质就是bash的进程,创建的子进程,执行我们的代码,这个bash,也叫做命令行解释器,shell,是所有命令行解释器的统称。在LInux当中,一般使用的是bash。

那么一个bash是怎么创建子进程的呢?

使用系统调用来创建进程,比如说,我们执行./程序,其实就是相当于我们告诉系统,我们要执行这个程序。

接下来,我们来见一下子进程的创建。

接口:

fork()

作用是创建一个子进程。

返回-1则失败了,成功的话,给父进程返回子进程的pid,给子进程返回0 。

接下来,我们创建一个程序来创造子进程:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>int main()
{/*chdir("/");FILE *fp=fopen("log.txt","w");if(fp==NULL){}*/printf("I am a process pid %d ppid %d\n",getpid(),getppid());pid_t id = fork();(void)id;printf("I am a 分支 pid %d ppid %d \n",getpid(),getppid());/*pid_t ppid =getppid();pid_t id = getpid();while(1){printf("hello bit,i am a process pid: %d,ppid: %d\n",id,ppid);sleep(1);}*/return 0;
}

这个是代码的运行结果:

 经过fork之后,有了两个执行分支,一个调用printf,另外一个也调用printf,这两个分支之间也是父子关系,一个是父进程(自己),一个子进程(fork创建的),一个父进程是可以创建出多个子进程的,所以进程其实也是树形结构。

我们接下来看下面的这段代码:

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int gval=0;int main()
{printf("i am a process, pid: %d,ppid: %d\n",getpid(),getppid());pid_t id=fork();if(id > 0){while(1){printf("我是父进程,pid : %d,ppid:%d,ret id:%d %d\n",getpid(),getppid(),id,gval);gval+=1;sleep(1);}}else if(id==0){while(1){printf("我是子进程,pid : %d,ppid:%d,ret id:%d %d\n",getpid(),getppid(),id,gval);sleep(1);}}return 0;
}

我们可以看到,这两个死循环同时再跑->两个执行流同时在跑,if 和else if同时成立,从fork之后就会有两个进程,分布进行,fork有两个返回值,给父进程返回子进程的pid,给子进程返回0.

一个父进程有多个子进程,但是一个子进程只会有一个父进程

 fork函数

fork创建了一个进程,使得原本的一个进程变成了两个呈现父子关系的进程,一般而言,这两个进程之间的代码是会共享的,但是数据不会,数据会各自私有一份。

所以,进程=内核数据结构+代码和数据

我们每次给新进程创建PCB,可以子进程和父进程相比,并没有数据和代码从磁盘继承,只有内核数据结构,所以,系统要求子进程和父进程共享代码,数据是各自私有一份的。

为什么呢?

因为代码具有很强的独立性,多个进程之间运行互不影响,即便是父子,两个进程之间也有很强的独立性。

所以,代码虽然是共享的,但是是只读的,而数据是各自私有一份的。

Pid_t id =fork();

在这个函数当中,

  • id是一个变量
  • 返回的本质,就是向指定变量进行写入返回值数据
  • 打印的本质,就是读取 

 创建多进程

那么其实有一个很奇怪的点,就是fork怎么会有两个返回值呢?

其实就是因为多了一个进程,也就是多了一个task_struct,一般而言,子进程的task_struct是从父进程拷贝下来的,调整了新的task_struct的部分属性。

所以有一部分属性,父子进程是相同的,代码要指向同一块,但是pid不同。

当fork的时候,fork是一个系统调用,当我们return的时候,它们的核心工作已经做完了,父子进程都已经开始运行了。

return本身就是一行代码

而fork之后代码是会共享的,所以父进程执行一次return,子进程执行一次return。

那么fork之后,是哪个进程先运行呢? 这个其实是不确定的(有OS调度器自主决定)。

但是时间片可能是一个方面的影响因素。

 好了,本次的文章就到这里了,我们下次再见。 

关键字:免费软件英文_建筑设计招标网站_友情链接什么意思_网站推广app下载

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

责任编辑: