我与Linux的爱恋:进程|进程的查看与管理|创建进程


外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

🔥个人主页guoguoqiang. 🔥专栏Linux的学习

Alt


在这里插入图片描述

一、进程的概念

1.什么是进程

课本概念:程序的一个执行实例,正在执行的程序等
内核观点:担当分配系统资源(CPU时间,内存)的实体

简单来说,进程==PCB(进程控制块)+进程对应的代码和数据,一个进程对应一个PCB操作系统对进程的管理,最终变成对链表的增删查改。
注意:可执行程序加载到内存不是进程,只是进程对应的代码和数据

2.在这里插入代码片多进程管理

操作系统中可以存在大量的进程,操作系统需要管理这些进程,以确保系统资源(如CPU时间,内存等)的合理分配。管理进程的本质是对进程数据的管理

3.描述进程-PCB

进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。课本上称之为PCB(process control block), Linux操作系统下的PCB是: task_struct

struct task_struct {
    volatile long state;
    void *stack;
    atomic_t usage;
    unsigned int flags;     
    unsigned int ptrace;
    unsigned long ptrace_message;
    siginfo_t *last_siginfo; 
    int lock_depth;         
    // ... 其他属性
};

在Linux中描述进程的结构体叫做task_struct。
task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息(如进程状态、优先级、程序计数器、内存指针、上下文数据、I/O状态信息和记账信息等)
所有运行在系统里的进程都以task_struct链表的形式存在内核里。

2.查看进程与管理进程

1.使用指令查看进程

ps指令:
语法 ps[选项]
功能:显示当前终端会话中属于当前用户的进程列表
选项:
在这里插入图片描述

常见格式: ps -axj |head -1 && ps -ajx |grep可执行文件
在这里插入图片描述
也可以通过系统文件然后用pid查看 ls /proc/
在这里插入图片描述

2.通过系统调用函数查看pid

操作系统对进程进行管理,但是用户不能直接访问操作系统,因此需要使用系统提供的系统调用函数来管理进程。
查看pid的函数为 getpid();返回值为pid_t
可以通过man getpid 查询
在这里插入图片描述
在这里插入图片描述
发现通过命令查和通过通过系统调用查看的结果一样

3.杀进程

方法1: crtl + c ;方法2: kill -9 pid
在这里插入图片描述
注意:kill掉任意一个进程不会影响另一个进程!!!(保证进程的独立性)

4.ppid(父进程id)

在这里插入图片描述
为什么进程每次启动pid会变,但是ppid不会变呢???

我们先查看一下父进程是什么,输入该命令: ps -axj | head -1 && ps -axj | grep ppid 通过查看可以看到该进程是bash进程(命令行解释器),因此就很好理解了。
在这里插入图片描述
当我们运行一个进程时,命令行解释器会把这个指令解释成bash的子进程。

接着再由这个bash的子进程执行对应的命令。

即:每一条命令被执行,都属于bash的子进程,只是子进程不一样。

为了更好看到执行程序与进程信息,可以使用shell脚本,隔一秒查一次进程

while : ; do ps ajx | head -1 && ps ajx | grep myprocess; sleep 1; done

3.创建进程

fork() 是 Unix 系统中用于创建新进程的系统调用。它会创建一个与当前进程几乎完全相同的新进程,新的进程称为子进程。父进程和子进程会继续从 fork() 调用的下一行代码开始执行。在这里插入图片描述

在 shell 中,你可以直接运行命令来创建进程。每个命令都会在系统中创建一个新进程。例如:

$ ls
$ gcc my_program.c -o my_program
$ ./my_program

这些命令分别创建了 ls、gcc 和 ./my_program 进程。每个命令的执行都涉及到创建一个新进程。

fork()的工作原理:
1.创建子进程

当进程调用 fork() 时,操作系统会创建一个新的进程,这个新的进程被称为子进程。子进程是父进程的几乎完整的拷贝,但有一些区别。
新进程会获得一个新的进程标识符(PID),这是与父进程不同的。

2.复制父进程的上下文

fork() 调用时,操作系统会复制父进程的内存空间、文件描述符、文件偏移量、信号处理器等信息到子进程中。这包括堆栈、代码段和数据段。
这称为“写时复制”(Copy-on-Write,COW)技术,实际上,操作系统在最初并不会立即复制内存中的所有数据,而是只在需要修改时才进行复制,以提高效率。

3.内存共享与复制

初始时,父进程和子进程共享相同的内存页。只有当其中一个进程试图修改这些页时,操作系统才会为该进程创建这些页的独立副本,这就是写时复制的机制。
这种机制可以节省内存和加快进程创建速度。

4.返回值

fork() 系统调用会在父进程和子进程中返回不同的值:
在父进程中,fork() 返回新创建的子进程的 PID。
在子进程中,fork()返回 0。
这个返回值可以用于区分父进程和子进程,进而决定不同的执行路径。

5.进程调度

在 fork() 之后,父进程和子进程将分别从 fork() 调用的下一行代码开始执行。操作系统的调度器会决定哪个进程先运行。

6.资源分配

子进程会继承父进程的所有资源描述符(如打开的文件描述符、信号处理器等),但这些描述符会有独立的引用计数。子进程和父进程的文件描述符指向同一个文件表项,因此对文件的读写操作可能会影响两个进程。

例子:

#include <stdio.h>    
#include <unistd.h>    
#include <sys/types.h>    
int main()    
{    
    fork();//创建进程    
    printf("hello world,pid: %d,ppid: %d\n",getpid(),getppid());//查看进程对应信息  
}

在这里插入图片描述

#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    pid_t pid = fork();  // 创建一个新进程

    if (pid < 0) {
        // fork 失败
        perror("fork failed");
        return 1;
    } else if (pid == 0) {
        // 子进程执行的代码
        printf("This is the child process. PID: %d\n", getpid());
    } else {
        // 父进程执行的代码
        printf("This is the parent process. PID: %d, Child PID: %d\n", getpid(), pid);
    }

    return 0;
}

在这里插入图片描述
正常一个if在c语言中只会执行一次,而这里执行了两次。说明有两个进程。

#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
 
int main()
{
 
	printf("process is running,only me!,pid: %d\n", getpid());
	sleep(3);
	pid_t id = fork();
	if (id == -1) return -1; //进程创建错误直接退出
	else if (id == 0)
	{
		//child 子进程代码
		while (1)
		{
			printf("id: %d,I am child process,pid: %d,ppid: %d\n", id, getpid(), getppid());
			sleep(1);
		}
	}
	else
	{
		//parent 父进程代码
		while (1)
		{
			printf("id: %d,I am parent,pid: %d,ppid: %d\n", id, getpid(), getppid());
			sleep(2);
		}
	}
	return 0;
}

在这里插入图片描述
一次性创建多个进程

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
void RunChild()
{
 
	while (1)
	{
		printf("I am a child process,pid: %d,ppid: %d\n", getpid(), getppid());
		sleep(1);
	}
}
int main()
{
	int num = 5;
 
	while(num--)
	{
		pid_t id = fork();
		if (id == 0)
		{
			RunChild();//运行子进程代码
		}
		sleep(1);
	}
 
	while (1)
	{
		sleep(1);
		printf("I am parent,pid: %d,ppid: %d\n", getpid(), getppid());
	}
	return 0;
}

在这里插入图片描述
为了更好看到执行程序与进程信息,可以使用shell脚本,隔一秒查一次进程,且不查看grep进程信息。

while : ; do ps ajx | head -1 && ps ajx | grep myprocess | grep -v grep; sleep 1; done

-v是反向选择
子进程”在操作系统中扮演着重要的角色,它们的创建和使用有很多实际的需求和好处。下面是一些主要的原因和应用场景,解释了为什么要为什么要创建子进程:

  1. 任务分离和并行处理
    任务分离:通过创建子进程,可以将复杂的任务分解成多个独立的子任务,从而提高程序的结构化和可维护性。例如,在 Web 服务器中,主进程可以处理网络连接,而每个子进程可以处理单独的请求,这样可以避免主进程因为某个请求的处理而阻塞。

并行处理:子进程可以在多核处理器上并行执行任务,提高程序的执行效率。利用子进程并行处理多个计算密集型任务,可以显著提升性能。例如,科学计算中的大量数据处理可以通过多个子进程并行执行。

  1. 避免阻塞
    非阻塞操作:在许多应用程序中,某些操作可能会阻塞主进程的执行。通过创建子进程,主进程可以继续执行其他任务而不会被阻塞。例如,数据库操作或长时间运行的网络请求可以放在子进程中处理,以避免影响主进程的响应能力。
    权限限制:子进程可以以不同的用户权限运行,从而限制对系统资源的访问
  2. 资源隔离
    资源管理:子进程可以拥有独立的资源和内存空间,避免了不同任务之间的干扰。例如,在进行文件操作时,如果文件处理出现问题,子进程的崩溃不会影响主进程的运行,这有助于提高系统的稳定性和鲁棒性。
  3. 安全性和隔离
    安全隔离:通过子进程,系统可以将不同的任务隔离开来,避免潜在的安全风险。例如,浏览器通常会为每个标签页创建独立的子进程,这样即使某个标签页出现了问题,也不会影响其他标签页或浏览器的主进程。
  4. 提高响应能力
    多任务处理:在用户交互密集的应用中(例如图形用户界面应用程序),创建子进程可以让主进程保持响应性。子进程可以处理后台任务或长时间运行的计算,从而确保主界面不会因为这些任务而变得不响应。
  5. 简化编程模型
    简化设计:在一些系统设计中,通过子进程可以简化任务的设计和管理。子进程的创建和管理可以使得系统的设计更加模块化、清晰。例如,在 Unix 系统中,守护进程(daemon)通常通过子进程机制来运行后台服务。
  6. 进程生命周期管理
    灵活性:子进程的创建和管理提供了灵活的进程生命周期控制。父进程可以在子进程完成任务后进行必要的清理和资源回收,或者根据子进程的执行结果决定后续的操作。
    总结
    创建子进程在现代操作系统中是一个强大且灵活的机制,允许程序以高效和结构化的方式处理多任务、多线程和资源隔离等复杂问题。通过使用子进程,系统能够提高响应能力、并行处理任务、增加安全性以及简化编程模型,从而实现更高效和稳定的软件系统。

4.task_struct内容分类

★标示符: 描述本进程的唯一标示符,用来区别其他进程。
★状态: 任务状态,退出代码,退出信号等。
★优先级: 相对于其他进程的优先级。
★程序计数器: 程序中即将被执行的下一条指令的地址。
★内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
★上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
★I/ O状态信息: 包括显示的I/O请求,分配给进程的I/ O设备和被进程使用的文件列表。
★记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
★其他信息

5.查看进程内容

◉ls /proc/pid -d # 按照目录查看

◉ ls /proc/pid -l # 查看进程内容

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
int main()
{
	while (1)
	{
		printf("I am process,pid: %d,ppid: %d\n", getpid(), getppid());
		sleep(1);
	}
	return 0;
}

在这里插入图片描述
cwd当前目录
exe对应的是可执行程序目录
1.如果我们在此处把可执行程序给删除,进程还会不会运行呢???

此处删除程序并不会造成影响,因为程序是加载到内存的,也就是内存拷贝了一份,这里是不会造成影响的,因为所占内存小,但如果内存过大运行就会出现问题

2.当前工作路径有什么用呢?

我们在C语言中学习文件操作,fopen(“log.txt”,“w”);默认是在当前目录创建文件,但是我们不一定每次都在当前目录创建文件,那怎么才能在其他目录下创建文件呢?

修改文件创建的路径,我们需要一个命令:chdir
在这里插入图片描述

#include<stdio.h>  
#include<unistd.h>  
   
int main()                                                                       
{  
  chdir("/home/gwq");//更改工作目录为/home/gwq
  FILE* pf = fopen("log.txt", "w");//创建文件  
  (void)pf;// ignore system warning   
  fclose(pf);  
   
  while (1)  
  {  
    printf("I am a process,pid: %d\n", getpid());      
    sleep(1);  
  }  
  return 0;  
}  

在这里插入图片描述
在这里插入图片描述
cwd当前目录 进程路径
exe对应的是可执行程序路径
因此我们对文件的理解不应该是在C语言上,而是应该在操作系统上

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值